mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Restore the CSS tokens and libraries removed since 1.5 as a deprecated layer (#3118)
This commit is contained in:
1 parent
c84c06be9f
commit
58e03a937c
51 files changed
+1060
-412
No files matched your search
@@ -25,12 +25,24 @@ Anything a user can write in their own project. If it is in the list, it cannot
|
||||
| Events | `change.bs.switch-icon` | renamed, no longer fired, fired at a different moment |
|
||||
| Files in the package | `dist/libs/litepicker/…`, `dist/css/tabler.rtl.css` | the path 404s after an update |
|
||||
| Dependencies | `dependencies`, `peerDependencies` | a user must install or uninstall something for the update to work |
|
||||
| Defaults | the gray scale, `forceFallback`, the color mode | an untouched project looks or behaves differently in a way the user did not ask for |
|
||||
| Behaviour defaults | `forceFallback`, the color mode, when a component starts | an untouched project behaves differently in a way the user did not ask for. How it **looks** is a separate rule, see below |
|
||||
| Browser support | `.browserslistrc` | the minimum version of any browser goes up |
|
||||
|
||||
Not public: anything under `preview/`, `docs/`, `shared/`, `.build/`, file layout inside `core/scss/` that is not reachable through `@use`, private `_underscore` members of JS classes, and the exact bytes of the compiled CSS.
|
||||
|
||||
Bug fixes are fine even when they change rendering, as long as the old behaviour was clearly wrong (a knob that did not move in RTL). When a fix changes how a correct page looks, treat it as a default change.
|
||||
Bug fixes are fine even when they change rendering, as long as the old behaviour was clearly wrong (a knob that did not move in RTL).
|
||||
|
||||
### Visual changes are allowed in a minor release
|
||||
|
||||
How Tabler looks is not frozen by semver. A minor release may change a color, a shadow, a spacing, a font, the shape of the focus ring or the default gray palette, the same way 1.5 moved to system fonts. The maintainers decided this on 2026-09-21. It holds as long as all of these are true:
|
||||
|
||||
- **Nothing the user wrote stops working.** The markup, the classes, the custom properties and the Sass variables they use still exist and still do their job. A redesign that renames or removes one is a rename or a removal, and needs an alias.
|
||||
- **An old token that the user set is still honoured.** When the focus ring became an outline, `--tblr-btn-focus-box-shadow` stopped being read. That part was a break, and `_deprecated.scss` draws the shadow again. Changing the default look is fine; ignoring the user's override is not.
|
||||
- **No layout a project depends on moves.** A different gray is visual. A component that is suddenly taller, or `position: absolute` where it was in the flow, breaks the pages built around it.
|
||||
- **Behaviour is not "visual".** What a click does, when an animation starts, which drag image the browser uses: those are behaviour defaults, and stay opt-in until the next major.
|
||||
- **It is listed.** Every visible change gets a bullet under "Visual changes" in the upgrade guide and a changeset that names it, so a user who sees a difference after updating can find out why. When the old look is cheap to keep, say how: a variable to set, or a theme in `tabler-themes.css`.
|
||||
|
||||
`check:compat` and `check:compat-fixture` do not look at pixels, so this rule is on the author and the reviewer.
|
||||
|
||||
## 2. Where compatibility code lives
|
||||
|
||||
@@ -40,10 +52,13 @@ Everything kept only for old projects goes into files named `deprecated`, so tha
|
||||
| --- | --- | --- |
|
||||
| `core/scss/_variables-deprecated.scss` | old `$variables`, each `!default`, with the default they had when they were removed | `@use … with ($x: …)` on a variable that does not exist is a compile error, and so is reading one, so the variable has to stay declared. Forwarded from `_config.scss` **after** `variables`, because old defaults are built from current ones. Nothing in Tabler reads these; `_deprecated.scss` compares each with its default and, when a project changed it, emits the matching new token. The file is excluded from `lint:scss:vars` |
|
||||
| `core/scss/mixins/_deprecated.scss` | old functions and mixins as thin wrappers around the new ones | emits no CSS; forwarded from `_mixins.scss`. A mixin calls `@include deprecate('<name>', '<since>', '<removed in>')` from `mixins/bootstrap/_deprecate.scss`; a function cannot include a mixin, so it calls the private `-deprecated()` helper in the same file. Either way the user gets a warning when compiling |
|
||||
| `core/scss/_deprecated.scss` | everything that emits CSS: class aliases (`.form-hint`, `.legend:empty`), old custom properties such as `--tblr-*-rgb`, hooks like `box-shadow: var(--btn-focus-box-shadow, none)` | loaded last from `tabler.scss`, next to `_extends.scss`: an alias built with `@extend` needs the whole `core` upstream. The whole file sits inside `@if $enable-deprecated { … }` |
|
||||
| `core/scss/_deprecated.scss` | everything that emits CSS: class aliases (`.form-hint`, `.legend:empty`), old custom properties, hooks like `box-shadow: var(--btn-focus-box-shadow, var(--btn-box-shadow))`, and the wiring from a customised old Sass variable to its new token | forwarded last from `tabler.scss`, after `_extends.scss`. It `@use`s `core`, because an alias built with `@extend` only reaches modules upstream of it. The whole file sits inside `@if $enable-deprecated { … }` |
|
||||
| `core/scss/_deprecated-props.scss` | the `--tblr-*-rgb` triplets, as mixins | three bundles emit them (`tabler.css`, `tabler-props.css`, `tabler-themes.css`), and a module that `@use`s `core` cannot be loaded from the small ones. This module emits nothing by itself |
|
||||
| `core/js/src/deprecated.ts` | old exports and globals, such as the `tabler` namespace with `getColor()` | one import to delete in the next major |
|
||||
|
||||
Create a file the first time you need it. `$enable-deprecated: true !default` lives in `_variables.scss`, next to `$enable-deprecation-messages`. A project that has migrated sets it to `false` and gets the bytes back; the next major flips the default, and the one after deletes the files.
|
||||
`$enable-deprecated: true !default` lives in `_variables.scss`, next to `$enable-deprecation-messages`. A project that has migrated sets it to `false` and gets about 1.4 kB (gzip) back; the next major flips the default, and the one after deletes the files.
|
||||
|
||||
A hook must not change a project that never used the old token. Give `var()` the value the element has anyway as its fallback, not `none`, and check it in the browser: `.btn:focus-visible { box-shadow: var(--btn-focus-box-shadow, none) }` would strip the shadow from every focused button.
|
||||
|
||||
Some compatibility cannot move into those files: a fallback inside a component rule (`mask-image: var(--form-check-bg-image, <default>)`), an old parameter in a mixin signature, a default value that was put back. Mark each of those where it is, with one fixed comment:
|
||||
|
||||
@@ -51,7 +66,7 @@ Some compatibility cannot move into those files: a fallback inside a component r
|
||||
// deprecated(2.0): `$show-border` is the old name of `$offset`
|
||||
```
|
||||
|
||||
`grep -rn "deprecated(2.0)" core/` plus the four files is then the full list of what the next major removes.
|
||||
`grep -rn "deprecated(2.0)" core/ .build/` plus the five files is then the full list of what the next major removes.
|
||||
|
||||
## 3. How to make the change compatible
|
||||
|
||||
@@ -79,7 +94,7 @@ Adding is safe, with one trap: a name that fits an existing pattern may already
|
||||
|
||||
### Change a default
|
||||
|
||||
Keep the old default and make the new behaviour opt-in: a class, an attribute, an option or a Sass variable. The new default can flip in the next major.
|
||||
For behaviour, keep the old default and make the new one opt-in: a class, an attribute, an option or a Sass variable. The new default can flip in the next major. A default that only changes how things look may change in a minor release, under the rule in section 1.
|
||||
|
||||
### Drop a bundled library or a file
|
||||
|
||||
@@ -112,7 +127,15 @@ It reports what the release has and the build lost, one key per line:
|
||||
|
||||
Fix each one with the patterns from section 3, then run it again. Known breaks are listed in `.build/compat-baseline.txt`; when you fix one, delete its line, or the check fails on the stale entry. Never add a line to the baseline to make a PR green. A line gets ` # accepted: <why>` only after the maintainers decided to ship that break. CI runs the check after the build, and with `--strict` on the versions pull request, so a release cannot be merged while an unaccepted line is left.
|
||||
|
||||
The check cannot see everything. It does not know about data attributes and their options, events, default values, a Sass variable whose type changed, or behaviour. For those, read the diff against the release tag with the table from section 1 in hand:
|
||||
`check:compat` compares names. `check:compat-fixture` covers behaviour: `.build/compat-fixture/` is a small project written the way a user of the last release would write it (`@use … with` on old variables, old functions, `rgba(var(--tblr-primary-rgb), .5)`, an empty `.legend`, the libraries in `dist/libs`, `tabler.tabler.getColor()`), and the check runs it against the release and against the working tree. Every assertion has to give the same answer on both.
|
||||
|
||||
```shell
|
||||
pnpm run check:compat-fixture
|
||||
```
|
||||
|
||||
Do not edit the fixture to make it pass: it stands for code you cannot reach. Add to it when a break got through that a real project would have hit. `--package <dir>` runs it against another checkout.
|
||||
|
||||
Even the two checks together cannot see everything. They do not know about data attributes and their options, events, default values, a Sass variable whose type changed, or behaviour. For those, read the diff against the release tag with the table from section 1 in hand:
|
||||
|
||||
```shell
|
||||
git diff "@tabler/core@$(npm view @tabler/core version)"..HEAD -- core/scss/_variables.scss core/js .browserslistrc
|
||||
@@ -127,3 +150,13 @@ git diff "@tabler/core@$(npm view @tabler/core version)"..HEAD -- core/scss/_var
|
||||
## 6. When a break cannot be avoided
|
||||
|
||||
Some changes have no alias: dropping a whole color model, raising the browser floor, removing a dependency users import. Those belong to the next major release, not to `dev`. Say so in the PR, and do not split the change to sneak half of it into a minor. If you are unsure whether something is a break, assume it is and ask.
|
||||
|
||||
### A documented exception
|
||||
|
||||
Only the maintainers can decide to ship a break in a minor release, and it takes all three of these:
|
||||
|
||||
1. a line per item in `.build/compat-baseline.txt` with `# accepted: <why>`, under a comment that says who decided and when,
|
||||
2. a section in the upgrade guide that says plainly what stops working and shows the fix,
|
||||
3. a check that keeps the exception from growing.
|
||||
|
||||
1.6 has one. Moving color mixing to the browser turned 69 Sass variables from colors into `color-mix()` strings: the `*-bg-subtle`, `*-text-emphasis` and `*-border-subtle` families with their `-dark` twins, `$body-secondary-color`, `$body-tertiary-color`, `$input-focus-border-color`, the dark border colors and a few navbar, dropdown and switch colors. `darken($primary-bg-subtle, 5%)` in a project no longer compiles, and no alias can change a type back. The theme colors, the grays, `$body-color`, `$body-bg` and `$link-color` are still colors. `check:compat` lists each one as `sass-type:$name`, and fails when another color variable stops being one. Do not add to that list: a new variable that needs a runtime value gets a new name, and the old one keeps its color.
|
||||
@@ -16,7 +16,7 @@ docs/content/ui/getting-started/upgrade/
|
||||
1-6.mdx # "Upgrade to 1.6", order: 1
|
||||
```
|
||||
|
||||
A release with no breaking change gets no page. Say so in the changelog instead.
|
||||
A patch or minor release must not break anything (see the `backward-compat` skill), so its guide lists **deprecations**: what still works, what replaces it, and when it goes away. Say "deprecated" and "the old name still works", never "removed" or "gone", and check each claim with `pnpm run check:compat`. Breaking changes, with "you need to", belong to the guide of a major release. A release with nothing deprecated and nothing visible gets no page. Say so in the changelog instead.
|
||||
|
||||
## 1. Collect the facts first
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
// Runs a project written for the last release against that release and against
|
||||
// the working tree, and fails when the two disagree.
|
||||
//
|
||||
// `check-compat` compares names: it knows that `--tblr-primary-rgb` still
|
||||
// exists, not that `rgba(var(--tblr-primary-rgb), 0.5)` still paints. This check
|
||||
// covers behaviour: the project in `.build/compat-fixture/` compiles its Sass
|
||||
// with 1.5 variables and helpers, and its page uses 1.5 markup, the libraries in
|
||||
// `dist/libs` and the old JavaScript helpers. Every assertion has to give the
|
||||
// same answer on both packages.
|
||||
//
|
||||
// The release is checked too, on purpose: an assertion that fails there is a
|
||||
// mistake in the fixture, not a break, and would otherwise hide one.
|
||||
//
|
||||
// Needs `core/dist`, so run it after the core build.
|
||||
//
|
||||
// Usage: tsx .build/check-compat-fixture.ts [--package <dir>]
|
||||
//
|
||||
// `--package` points at another unpacked or built `@tabler/core` instead of
|
||||
// `core/`, for example an older checkout. Without a `dist/` in it only the Sass
|
||||
// half runs.
|
||||
import { createReadStream, existsSync, statSync } from 'node:fs'
|
||||
import { createServer, type Server } from 'node:http'
|
||||
import { extname, join, resolve } from 'node:path'
|
||||
import { chromium, type Page } from 'playwright'
|
||||
import { compile as compileSass } from 'sass'
|
||||
import { pkgName, releasedPackage } from './released-package'
|
||||
|
||||
const fixtureDir = '.build/compat-fixture'
|
||||
const packageArg = process.argv.indexOf('--package')
|
||||
const coreDir = packageArg > -1 ? process.argv[packageArg + 1]! : 'core'
|
||||
|
||||
const MIME: Record<string, string> = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.svg': 'image/svg+xml', '.map': 'application/json' }
|
||||
|
||||
type Result = Record<string, string>
|
||||
|
||||
// --- sass ------------------------------------------------------------------
|
||||
|
||||
function sassResults(pkg: string): Result {
|
||||
const results: Result = {}
|
||||
try {
|
||||
const { css } = compileSass(join(fixtureDir, 'project.scss'), { loadPaths: [pkg, 'node_modules'], style: 'expanded', quietDeps: true, logger: { warn() {}, debug() {} } })
|
||||
results['sass: the project compiles'] = 'yes'
|
||||
|
||||
const fixture = /\.fixture \{([^}]*)\}/.exec(css)?.[1] ?? ''
|
||||
const value = (name: string): string => new RegExp(`${name}:\\s*([^;]+);`).exec(fixture)?.[1]?.trim() ?? '(missing)'
|
||||
results['sass: $input-focus-width follows $input-btn-focus-width'] = value('--fixture-width')
|
||||
results['sass: $theme-colors-rgb has the primary colour'] = value('--fixture-has-rgb-map')
|
||||
results['sass: theme-color-darker() returns a colour'] = /^(#|rgb|oklch|color)/.test(value('color')) ? 'yes' : value('color')
|
||||
results['sass: theme-color-lighter() takes the $primary variable'] = /^(#|rgb|oklch|color)/.test(value('border-color')) ? 'yes' : value('border-color')
|
||||
results['sass: url-svg() builds a data uri'] = value('background-image').startsWith('url(') ? 'yes' : value('background-image')
|
||||
results['sass: varify() wraps names in var()'] = value('transition-property')
|
||||
results['sass: media-breakpoint-down-than(md) emits a media query'] = /@media \(max-width: 575\.98px\)\s*\{\s*\.fixture/.test(css) ? 'yes' : 'no'
|
||||
results['sass: focus-ring($show-border: true) emits a focus style'] = /\.fixture:focus \{[^}]*(outline|box-shadow)/.test(css) ? 'yes' : 'no'
|
||||
} catch (error) {
|
||||
results['sass: the project compiles'] = `no — ${String((error as Error).message).split('\n')[0]}`
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// --- page ------------------------------------------------------------------
|
||||
|
||||
function serve(pkg: string): Promise<Server> {
|
||||
const server = createServer((request, response) => {
|
||||
const path = decodeURIComponent((request.url ?? '/').split('?')[0]!)
|
||||
const file = path === '/' ? resolve(fixtureDir, 'page.html') : resolve(pkg, `.${path}`)
|
||||
if (!existsSync(file) || !statSync(file).isFile()) {
|
||||
response.writeHead(404).end()
|
||||
return
|
||||
}
|
||||
response.writeHead(200, { 'content-type': MIME[extname(file)] ?? 'application/octet-stream' })
|
||||
createReadStream(file).pipe(response)
|
||||
})
|
||||
return new Promise((done) => server.listen(0, '127.0.0.1', () => done(server)))
|
||||
}
|
||||
|
||||
async function pageResults(pkg: string, page: Page): Promise<Result> {
|
||||
const results: Result = {}
|
||||
const problems: string[] = []
|
||||
page.on('pageerror', (error) => problems.push(error.message))
|
||||
page.on('response', (response) => {
|
||||
if (response.status() >= 400) problems.push(`${response.status()} ${new URL(response.url()).pathname}`)
|
||||
})
|
||||
|
||||
const server = await serve(pkg)
|
||||
const { port } = server.address() as { port: number }
|
||||
await page.goto(`http://127.0.0.1:${port}/`, { waitUntil: 'networkidle' })
|
||||
await page.addStyleTag({ content: '*, *::before, *::after { transition: none !important; }' })
|
||||
|
||||
const style = (selector: string, property: string): Promise<string> => page.evaluate(([s, p]) => getComputedStyle(document.querySelector(s!)!).getPropertyValue(p!), [selector, property])
|
||||
|
||||
results['page: no script error and no 404'] = problems.length === 0 ? 'yes' : problems.join('; ')
|
||||
results['page: rgba(var(--tblr-primary-rgb), .5) paints'] = await style('#highlight', 'background-color')
|
||||
results['page: an empty .legend is a visible dot'] = (await page.evaluate(() => document.querySelector('#legend')!.getBoundingClientRect().width)) > 0 ? 'yes' : 'no'
|
||||
results['page: .form-hint is a block'] = await style('#hint', 'display')
|
||||
results['page: .form-hint sits below the control'] = (await page.evaluate(() => document.querySelector('#hint')!.getBoundingClientRect().top >= document.querySelector('#email')!.getBoundingClientRect().bottom)) ? 'yes' : 'no'
|
||||
|
||||
await page.focus('#button')
|
||||
await page.keyboard.press('Shift+Tab')
|
||||
await page.keyboard.press('Tab')
|
||||
results['page: --tblr-btn-focus-box-shadow is drawn on focus'] = (await style('#button', 'box-shadow')).includes('rgb(255, 0, 0)') ? 'yes' : await style('#button', 'box-shadow')
|
||||
|
||||
results['page: window.tabler.Modal exists'] = await page.evaluate(() => typeof (window as any).tabler?.Modal)
|
||||
results['page: tabler.tabler.prefix'] = await page.evaluate(() => String((window as any).fixture?.prefix))
|
||||
results['page: tabler.tabler.getColor() returns a colour'] = (await page.evaluate(() => Boolean((window as any).fixture?.color))) ? 'yes' : 'no'
|
||||
results['page: tabler.tabler.getColor(name, 0.5) returns a colour'] = (await page.evaluate(() => Boolean((window as any).fixture?.colorHalf))) ? 'yes' : 'no'
|
||||
|
||||
for (const name of ['autosize', 'countUp', 'ClipboardJS', 'Litepicker']) {
|
||||
results[`page: dist/libs provides window.${name}`] = await page.evaluate((n) => typeof (window as any)[n] !== 'undefined', name).then((ok) => (ok ? 'yes' : 'no'))
|
||||
}
|
||||
results['page: Litepicker renders with Tabler styles'] = (await page.evaluate(() => {
|
||||
const picker = document.querySelector('.litepicker')
|
||||
return picker ? getComputedStyle(picker).getPropertyValue('--litepicker-day-color').trim() !== '' : false
|
||||
}))
|
||||
? 'yes'
|
||||
: 'no'
|
||||
|
||||
await page.fill('#message', 'one\ntwo\nthree\nfour\nfive\nsix')
|
||||
await page.dispatchEvent('#message', 'input')
|
||||
results['page: data-bs-toggle="autosize" grows the textarea'] = (await page.evaluate(() => (document.querySelector('#message') as HTMLElement).offsetHeight)) > 60 ? 'yes' : 'no'
|
||||
|
||||
await page.waitForTimeout(600)
|
||||
results['page: data-countup ends on the number'] = (await page.textContent('#total'))?.replace(/\D/g, '') ?? ''
|
||||
|
||||
await page.click('#open-modal')
|
||||
await page.waitForTimeout(100)
|
||||
results['page: data-bs-toggle="modal" opens the modal'] = (await page.evaluate(() => document.querySelector('#modal')!.classList.contains('show'))) ? 'yes' : 'no'
|
||||
|
||||
server.close()
|
||||
return results
|
||||
}
|
||||
|
||||
// --- main ------------------------------------------------------------------
|
||||
|
||||
async function main() {
|
||||
const hasDist = existsSync(join(coreDir, 'dist/css/tabler.css'))
|
||||
if (!hasDist && packageArg === -1) {
|
||||
throw new Error('core/dist is missing — build core first: pnpm --filter @tabler/core build')
|
||||
}
|
||||
|
||||
const { dir: released, version } = await releasedPackage()
|
||||
const browser = await chromium.launch()
|
||||
const run = async (pkg: string): Promise<Result> => {
|
||||
const page = await browser.newPage()
|
||||
const results = { ...sassResults(pkg), ...(hasDist ? await pageResults(pkg, page) : {}) }
|
||||
await page.close()
|
||||
return results
|
||||
}
|
||||
const before = await run(released)
|
||||
const after = await run(coreDir)
|
||||
await browser.close()
|
||||
|
||||
const failed: string[] = []
|
||||
for (const [name, expected] of Object.entries(before)) {
|
||||
const actual = after[name] ?? '(not run)'
|
||||
const ok = actual === expected
|
||||
console.log(`${ok ? '✓' : '✗'} ${name}${ok ? '' : `\n ${pkgName}@${version}: ${expected}\n working tree: ${actual}`}`)
|
||||
if (!ok) failed.push(name)
|
||||
}
|
||||
|
||||
// The fixture is only worth something if the release passes it.
|
||||
const broken = Object.entries(before).filter(([, value]) => value.startsWith('no') || value === '(missing)' || value === 'undefined')
|
||||
for (const [name, value] of broken) console.error(`\n! ${name} fails on ${pkgName}@${version} itself (${value}) — fix the fixture.`)
|
||||
|
||||
if (failed.length > 0) console.error(`\n${failed.length} of ${Object.keys(before).length} checks behave differently from ${pkgName}@${version}. See the backward-compat skill.`)
|
||||
if (failed.length > 0 || broken.length > 0) process.exit(1)
|
||||
console.log(`\nOK — a ${version} project compiles and behaves the same on the working tree (${Object.keys(before).length} checks).`)
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
+32
-34
@@ -7,8 +7,10 @@
|
||||
// release of `@tabler/core` from npm and compares its public surface with the
|
||||
// working tree:
|
||||
//
|
||||
// css classes and `--tblr-*` custom properties of every dist/css/*.css
|
||||
// css classes and custom properties of every dist/css/*.css
|
||||
// sass `$variables`, and `@function` / `@mixin` names and parameters, in scss/
|
||||
// sass-type a variable that was a Sass colour and is now a string: `darken($x, 5%)`
|
||||
// in a project stops compiling, and no alias can fix a type
|
||||
// js top-level exports of dist/js/tabler.esm.js
|
||||
// file every path under dist/ (libs, images, types), and scss/ partials
|
||||
//
|
||||
@@ -22,42 +24,15 @@
|
||||
// skill for how to fix what it reports.
|
||||
//
|
||||
// Usage: tsx .build/check-compat.ts [--strict]
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
||||
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
|
||||
import { join, relative } from 'node:path'
|
||||
import { compileString } from 'sass'
|
||||
import { pkgName, releasedPackage } from './released-package'
|
||||
|
||||
const pkgName = '@tabler/core'
|
||||
const coreDir = 'core'
|
||||
const baselineFile = '.build/compat-baseline.txt'
|
||||
const cacheDir = 'node_modules/.cache/check-compat'
|
||||
const strict = process.argv.includes('--strict')
|
||||
|
||||
const registry = 'https://registry.npmjs.org'
|
||||
|
||||
async function releasedDir(): Promise<{ dir: string; version: string }> {
|
||||
const local = JSON.parse(readFileSync(join(coreDir, 'package.json'), 'utf8')).version as string
|
||||
// On the versions PR the local version is not published yet: compare with `latest`.
|
||||
let version = local
|
||||
let response = await fetch(`${registry}/${pkgName}/${version}`)
|
||||
if (response.status === 404) {
|
||||
response = await fetch(`${registry}/${pkgName}/latest`)
|
||||
}
|
||||
if (!response.ok) throw new Error(`npm registry answered ${response.status} for ${pkgName}`)
|
||||
const manifest = (await response.json()) as { version: string; dist: { tarball: string } }
|
||||
version = manifest.version
|
||||
|
||||
const dir = join(cacheDir, version)
|
||||
if (!existsSync(join(dir, 'package', 'package.json'))) {
|
||||
mkdirSync(dir, { recursive: true })
|
||||
const tarball = await fetch(manifest.dist.tarball)
|
||||
if (!tarball.ok) throw new Error(`could not download ${manifest.dist.tarball}: ${tarball.status}`)
|
||||
const archive = join(dir, 'package.tgz')
|
||||
writeFileSync(archive, Buffer.from(await tarball.arrayBuffer()))
|
||||
execFileSync('tar', ['-xzf', archive, '-C', dir])
|
||||
}
|
||||
return { dir: join(dir, 'package'), version }
|
||||
}
|
||||
|
||||
function walk(root: string, dir = root): string[] {
|
||||
if (!existsSync(dir)) return []
|
||||
return readdirSync(dir).flatMap((name) => {
|
||||
@@ -72,7 +47,9 @@ const matches = (source: string, pattern: RegExp): Set<string> => new Set([...so
|
||||
|
||||
// A class is a dot followed by an identifier; `1.5rem` and `url(a.svg)` are not.
|
||||
const cssClass = /(?<![\w)\]"'-])\.(-?[a-zA-Z_][\w-]*)/g
|
||||
const cssProperty = /(--tblr-[\w-]+)/g
|
||||
// Every custom property, not only `--tblr-*`: a vendor name that gained the
|
||||
// prefix (`--litepicker-*`) is as broken as one that disappeared.
|
||||
const cssProperty = /(?<![\w-])(--[a-zA-Z][\w-]*)/g
|
||||
|
||||
const stripCssNoise = (css: string): string => css.replace(/\/\*[\s\S]*?\*\//g, '').replace(/url\([^)]*\)/g, 'url()')
|
||||
|
||||
@@ -163,6 +140,27 @@ function sassBreaks(released: string, current: string): string[] {
|
||||
return breaks
|
||||
}
|
||||
|
||||
// --- sass types ------------------------------------------------------------
|
||||
|
||||
// The type of every variable the config module exposes, read by Sass itself.
|
||||
function sassTypes(root: string): Map<string, string> {
|
||||
const source = `
|
||||
@use 'sass:meta';
|
||||
@use 'scss/config' as config;
|
||||
a {
|
||||
@each $name, $value in meta.module-variables('config') {
|
||||
--#{$name}: #{meta.type-of($value)};
|
||||
}
|
||||
}`
|
||||
const { css } = compileString(source, { loadPaths: [root, 'node_modules'], logger: { warn() {}, debug() {} } })
|
||||
return new Map([...css.matchAll(/--([\w-]+): (\w+);/g)].map((match) => [match[1]!, match[2]!]))
|
||||
}
|
||||
|
||||
function sassTypeBreaks(released: string, current: string): string[] {
|
||||
const after = sassTypes(current)
|
||||
return [...sassTypes(released)].filter(([name, type]) => type === 'color' && after.has(name) && after.get(name) !== 'color').map(([name]) => `sass-type:$${name}`)
|
||||
}
|
||||
|
||||
// --- js --------------------------------------------------------------------
|
||||
|
||||
function esmExports(file: string): Set<string> {
|
||||
@@ -209,8 +207,8 @@ async function main() {
|
||||
throw new Error('core/dist is missing — build core first: pnpm --filter @tabler/core build')
|
||||
}
|
||||
|
||||
const { dir: released, version } = await releasedDir()
|
||||
const breaks = new Set([...cssBreaks(released, coreDir), ...sassBreaks(released, coreDir), ...jsBreaks(released, coreDir), ...fileBreaks(released, coreDir)])
|
||||
const { dir: released, version } = await releasedPackage()
|
||||
const breaks = new Set([...cssBreaks(released, coreDir), ...sassBreaks(released, coreDir), ...sassTypeBreaks(released, coreDir), ...jsBreaks(released, coreDir), ...fileBreaks(released, coreDir)])
|
||||
|
||||
const baseline = new Map<string, boolean>() // key → accepted
|
||||
for (const line of readFileSync(baselineFile, 'utf8').split('\n')) {
|
||||
|
||||
+85
-207
@@ -10,213 +10,91 @@
|
||||
#
|
||||
# Everything below entered `dev` between 1.5.1 and 1.6.0, before the check existed.
|
||||
|
||||
# RGB triplets of the colors, removed with the move to color-mix() (#3042)
|
||||
css:tabler-props.css:--tblr-azure-lt-rgb
|
||||
css:tabler-props.css:--tblr-azure-rgb
|
||||
css:tabler-props.css:--tblr-bitbucket-lt-rgb
|
||||
css:tabler-props.css:--tblr-bitbucket-rgb
|
||||
css:tabler-props.css:--tblr-blue-lt-rgb
|
||||
css:tabler-props.css:--tblr-blue-rgb
|
||||
css:tabler-props.css:--tblr-cyan-lt-rgb
|
||||
css:tabler-props.css:--tblr-cyan-rgb
|
||||
css:tabler-props.css:--tblr-danger-lt-rgb
|
||||
css:tabler-props.css:--tblr-danger-rgb
|
||||
css:tabler-props.css:--tblr-dark-lt-rgb
|
||||
css:tabler-props.css:--tblr-dark-rgb
|
||||
css:tabler-props.css:--tblr-dribbble-lt-rgb
|
||||
css:tabler-props.css:--tblr-dribbble-rgb
|
||||
css:tabler-props.css:--tblr-facebook-lt-rgb
|
||||
css:tabler-props.css:--tblr-facebook-rgb
|
||||
css:tabler-props.css:--tblr-flickr-lt-rgb
|
||||
css:tabler-props.css:--tblr-flickr-rgb
|
||||
css:tabler-props.css:--tblr-github-lt-rgb
|
||||
css:tabler-props.css:--tblr-github-rgb
|
||||
css:tabler-props.css:--tblr-google-lt-rgb
|
||||
css:tabler-props.css:--tblr-google-rgb
|
||||
css:tabler-props.css:--tblr-green-lt-rgb
|
||||
css:tabler-props.css:--tblr-green-rgb
|
||||
css:tabler-props.css:--tblr-indigo-lt-rgb
|
||||
css:tabler-props.css:--tblr-indigo-rgb
|
||||
css:tabler-props.css:--tblr-info-lt-rgb
|
||||
css:tabler-props.css:--tblr-info-rgb
|
||||
css:tabler-props.css:--tblr-instagram-lt-rgb
|
||||
css:tabler-props.css:--tblr-instagram-rgb
|
||||
css:tabler-props.css:--tblr-light-lt-rgb
|
||||
css:tabler-props.css:--tblr-light-rgb
|
||||
css:tabler-props.css:--tblr-lime-lt-rgb
|
||||
css:tabler-props.css:--tblr-lime-rgb
|
||||
css:tabler-props.css:--tblr-linkedin-lt-rgb
|
||||
css:tabler-props.css:--tblr-linkedin-rgb
|
||||
css:tabler-props.css:--tblr-muted-lt-rgb
|
||||
css:tabler-props.css:--tblr-muted-rgb
|
||||
css:tabler-props.css:--tblr-orange-lt-rgb
|
||||
css:tabler-props.css:--tblr-orange-rgb
|
||||
css:tabler-props.css:--tblr-pink-lt-rgb
|
||||
css:tabler-props.css:--tblr-pink-rgb
|
||||
css:tabler-props.css:--tblr-pinterest-lt-rgb
|
||||
css:tabler-props.css:--tblr-pinterest-rgb
|
||||
css:tabler-props.css:--tblr-primary-lt-rgb
|
||||
css:tabler-props.css:--tblr-primary-rgb
|
||||
css:tabler-props.css:--tblr-purple-lt-rgb
|
||||
css:tabler-props.css:--tblr-purple-rgb
|
||||
css:tabler-props.css:--tblr-red-lt-rgb
|
||||
css:tabler-props.css:--tblr-red-rgb
|
||||
css:tabler-props.css:--tblr-rss-lt-rgb
|
||||
css:tabler-props.css:--tblr-rss-rgb
|
||||
css:tabler-props.css:--tblr-secondary-lt-rgb
|
||||
css:tabler-props.css:--tblr-secondary-rgb
|
||||
css:tabler-props.css:--tblr-success-lt-rgb
|
||||
css:tabler-props.css:--tblr-success-rgb
|
||||
css:tabler-props.css:--tblr-tabler-lt-rgb
|
||||
css:tabler-props.css:--tblr-tabler-rgb
|
||||
css:tabler-props.css:--tblr-teal-lt-rgb
|
||||
css:tabler-props.css:--tblr-teal-rgb
|
||||
css:tabler-props.css:--tblr-twitter-lt-rgb
|
||||
css:tabler-props.css:--tblr-twitter-rgb
|
||||
css:tabler-props.css:--tblr-vimeo-lt-rgb
|
||||
css:tabler-props.css:--tblr-vimeo-rgb
|
||||
css:tabler-props.css:--tblr-vk-lt-rgb
|
||||
css:tabler-props.css:--tblr-vk-rgb
|
||||
css:tabler-props.css:--tblr-warning-lt-rgb
|
||||
css:tabler-props.css:--tblr-warning-rgb
|
||||
css:tabler-props.css:--tblr-x-lt-rgb
|
||||
css:tabler-props.css:--tblr-x-rgb
|
||||
css:tabler-props.css:--tblr-yellow-lt-rgb
|
||||
css:tabler-props.css:--tblr-yellow-rgb
|
||||
css:tabler-props.css:--tblr-youtube-lt-rgb
|
||||
css:tabler-props.css:--tblr-youtube-rgb
|
||||
css:tabler-themes.css:--tblr-primary-rgb
|
||||
css:tabler.css:--tblr-azure-lt-rgb
|
||||
css:tabler.css:--tblr-azure-rgb
|
||||
css:tabler.css:--tblr-bitbucket-lt-rgb
|
||||
css:tabler.css:--tblr-bitbucket-rgb
|
||||
css:tabler.css:--tblr-black-rgb
|
||||
css:tabler.css:--tblr-blue-lt-rgb
|
||||
css:tabler.css:--tblr-blue-rgb
|
||||
css:tabler.css:--tblr-body-bg-rgb
|
||||
css:tabler.css:--tblr-body-color-rgb
|
||||
css:tabler.css:--tblr-cyan-lt-rgb
|
||||
css:tabler.css:--tblr-cyan-rgb
|
||||
css:tabler.css:--tblr-danger-lt-rgb
|
||||
css:tabler.css:--tblr-danger-rgb
|
||||
css:tabler.css:--tblr-dark-lt-rgb
|
||||
css:tabler.css:--tblr-dark-rgb
|
||||
css:tabler.css:--tblr-dribbble-lt-rgb
|
||||
css:tabler.css:--tblr-dribbble-rgb
|
||||
css:tabler.css:--tblr-emphasis-color-rgb
|
||||
css:tabler.css:--tblr-facebook-lt-rgb
|
||||
css:tabler.css:--tblr-facebook-rgb
|
||||
css:tabler.css:--tblr-flickr-lt-rgb
|
||||
css:tabler.css:--tblr-flickr-rgb
|
||||
css:tabler.css:--tblr-github-lt-rgb
|
||||
css:tabler.css:--tblr-github-rgb
|
||||
css:tabler.css:--tblr-google-lt-rgb
|
||||
css:tabler.css:--tblr-google-rgb
|
||||
css:tabler.css:--tblr-green-lt-rgb
|
||||
css:tabler.css:--tblr-green-rgb
|
||||
css:tabler.css:--tblr-indigo-lt-rgb
|
||||
css:tabler.css:--tblr-indigo-rgb
|
||||
css:tabler.css:--tblr-info-lt-rgb
|
||||
css:tabler.css:--tblr-info-rgb
|
||||
css:tabler.css:--tblr-instagram-lt-rgb
|
||||
css:tabler.css:--tblr-instagram-rgb
|
||||
css:tabler.css:--tblr-light-lt-rgb
|
||||
css:tabler.css:--tblr-light-rgb
|
||||
css:tabler.css:--tblr-lime-lt-rgb
|
||||
css:tabler.css:--tblr-lime-rgb
|
||||
css:tabler.css:--tblr-link-color-rgb
|
||||
css:tabler.css:--tblr-link-hover-color-rgb
|
||||
css:tabler.css:--tblr-linkedin-lt-rgb
|
||||
css:tabler.css:--tblr-linkedin-rgb
|
||||
css:tabler.css:--tblr-muted-lt-rgb
|
||||
css:tabler.css:--tblr-muted-rgb
|
||||
css:tabler.css:--tblr-orange-lt-rgb
|
||||
css:tabler.css:--tblr-orange-rgb
|
||||
css:tabler.css:--tblr-pink-lt-rgb
|
||||
css:tabler.css:--tblr-pink-rgb
|
||||
css:tabler.css:--tblr-pinterest-lt-rgb
|
||||
css:tabler.css:--tblr-pinterest-rgb
|
||||
css:tabler.css:--tblr-primary-lt-rgb
|
||||
css:tabler.css:--tblr-primary-rgb
|
||||
css:tabler.css:--tblr-purple-lt-rgb
|
||||
css:tabler.css:--tblr-purple-rgb
|
||||
css:tabler.css:--tblr-red-lt-rgb
|
||||
css:tabler.css:--tblr-red-rgb
|
||||
css:tabler.css:--tblr-rss-lt-rgb
|
||||
css:tabler.css:--tblr-rss-rgb
|
||||
css:tabler.css:--tblr-secondary-bg-rgb
|
||||
css:tabler.css:--tblr-secondary-color-rgb
|
||||
css:tabler.css:--tblr-secondary-lt-rgb
|
||||
css:tabler.css:--tblr-secondary-rgb
|
||||
css:tabler.css:--tblr-status-color-rgb
|
||||
css:tabler.css:--tblr-success-lt-rgb
|
||||
css:tabler.css:--tblr-success-rgb
|
||||
css:tabler.css:--tblr-tabler-lt-rgb
|
||||
css:tabler.css:--tblr-tabler-rgb
|
||||
css:tabler.css:--tblr-teal-lt-rgb
|
||||
css:tabler.css:--tblr-teal-rgb
|
||||
css:tabler.css:--tblr-tertiary-bg-rgb
|
||||
css:tabler.css:--tblr-tertiary-color-rgb
|
||||
css:tabler.css:--tblr-twitter-lt-rgb
|
||||
css:tabler.css:--tblr-twitter-rgb
|
||||
css:tabler.css:--tblr-vimeo-lt-rgb
|
||||
css:tabler.css:--tblr-vimeo-rgb
|
||||
css:tabler.css:--tblr-vk-lt-rgb
|
||||
css:tabler.css:--tblr-vk-rgb
|
||||
css:tabler.css:--tblr-warning-lt-rgb
|
||||
css:tabler.css:--tblr-warning-rgb
|
||||
css:tabler.css:--tblr-white-rgb
|
||||
css:tabler.css:--tblr-x-lt-rgb
|
||||
css:tabler.css:--tblr-x-rgb
|
||||
css:tabler.css:--tblr-yellow-lt-rgb
|
||||
css:tabler.css:--tblr-yellow-rgb
|
||||
css:tabler.css:--tblr-youtube-lt-rgb
|
||||
css:tabler.css:--tblr-youtube-rgb
|
||||
# Custom properties
|
||||
css:tabler-props.css:--tblr-bg-surface-dark # accepted: only read there by --tblr-backdrop-bg; tabler.css still defines it
|
||||
|
||||
# Other custom properties: focus box-shadow tokens (#3098), form hint (#3059), masked icons (#3043)
|
||||
css:tabler-props.css:--tblr-bg-surface-dark
|
||||
css:tabler.css:--tblr-accordion-btn-focus-box-shadow
|
||||
css:tabler.css:--tblr-btn-close-focus-shadow
|
||||
css:tabler.css:--tblr-btn-focus-box-shadow
|
||||
css:tabler.css:--tblr-focus-ring-blur
|
||||
css:tabler.css:--tblr-focus-ring-x
|
||||
css:tabler.css:--tblr-focus-ring-y
|
||||
css:tabler.css:--tblr-form-check-bg-image
|
||||
css:tabler.css:--tblr-form-hint-control-margin-top
|
||||
css:tabler.css:--tblr-form-hint-label-offset
|
||||
css:tabler.css:--tblr-form-hint-margin-top
|
||||
css:tabler.css:--tblr-form-switch-bg
|
||||
css:tabler.css:--tblr-pagination-focus-box-shadow
|
||||
|
||||
# tabler-vendors.css: Litepicker styles (#3062) and overrides for classes of third-party libraries
|
||||
css:tabler-vendors.css:--tblr-bg-forms
|
||||
css:tabler-vendors.css:--tblr-info
|
||||
css:tabler-vendors.css:--tblr-light
|
||||
css:tabler-vendors.css:.apexcharts-yaxis-tick
|
||||
css:tabler-vendors.css:.button-next-month
|
||||
css:tabler-vendors.css:.button-previous-month
|
||||
css:tabler-vendors.css:.container__days
|
||||
css:tabler-vendors.css:.container__main
|
||||
css:tabler-vendors.css:.container__months
|
||||
css:tabler-vendors.css:.datepicker-inline
|
||||
css:tabler-vendors.css:.day-item
|
||||
css:tabler-vendors.css:.fslightbox-slash
|
||||
css:tabler-vendors.css:.fslightbox-slide-number-container
|
||||
css:tabler-vendors.css:.jvm-legend-inner
|
||||
css:tabler-vendors.css:.litepicker
|
||||
css:tabler-vendors.css:.month-item-name
|
||||
css:tabler-vendors.css:.month-item-weekdays-row
|
||||
css:tabler-vendors.css:.month-item-year
|
||||
css:tabler-vendors.css:.ts-input
|
||||
# tabler-vendors.css: overrides for classes that the libraries themselves dropped
|
||||
css:tabler-vendors.css:.apexcharts-yaxis-tick # accepted: override for a third-party class, not Tabler API
|
||||
css:tabler-vendors.css:.fslightbox-slash # accepted: override for a third-party class, not Tabler API
|
||||
css:tabler-vendors.css:.fslightbox-slide-number-container # accepted: override for a third-party class, not Tabler API
|
||||
css:tabler-vendors.css:.jvm-legend-inner # accepted: override for a third-party class, not Tabler API
|
||||
css:tabler-vendors.css:.ts-input # accepted: override for a third-party class, not Tabler API
|
||||
|
||||
# Files in the package
|
||||
file:dist/libs/autosize/LICENSE.md
|
||||
file:dist/libs/autosize/dist/autosize.min.js
|
||||
file:dist/libs/clipboard/LICENSE
|
||||
file:dist/libs/clipboard/dist/clipboard.min.js
|
||||
file:dist/libs/countup.js/LICENSE.md
|
||||
file:dist/libs/countup.js/dist/countUp.umd.js
|
||||
file:dist/libs/litepicker/LICENSE.md
|
||||
file:dist/libs/litepicker/dist/litepicker.js
|
||||
file:dist/types/src/tabler.d.ts
|
||||
file:scss/vendor/_litepicker.scss
|
||||
file:dist/types/src/tabler.d.ts # accepted: deep type path; the helpers are exported from dist/types/src/deprecated.d.ts
|
||||
|
||||
# Sass variables that were colours and are `color-mix()` or relative-colour strings
|
||||
# since #3042 and #3043. A Sass colour function on one of them no longer compiles,
|
||||
# and an alias cannot fix a type. Accepted by the maintainers on 2026-09-21 as the
|
||||
# one documented exception of 1.6: see "Variables that turned into color-mix()" in
|
||||
# the upgrade guide. The theme colours, the grays, `$body-color`, `$body-bg` and
|
||||
# `$link-color` are still colours, and the check fails if one more variable joins this list.
|
||||
sass-type:$blockquote-footer-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$body-secondary-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$body-secondary-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$body-tertiary-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$body-tertiary-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$border-active-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$border-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$border-dark-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$btn-link-disabled-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$danger-bg-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$danger-bg-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$danger-border-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$danger-border-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$danger-text-emphasis # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$danger-text-emphasis-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$dark-bg-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$darken-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$dropdown-dark-link-hover-bg # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$dropdown-header-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-check-input-focus-border # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-floating-label-disabled-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-invalid-border-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-invalid-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-range-thumb-active-bg # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-select-focus-border-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-switch-checked-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-switch-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-switch-focus-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-valid-border-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$form-valid-color-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$info-bg-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$info-bg-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$info-border-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$info-border-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$info-text-emphasis # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$info-text-emphasis-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$input-focus-border-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$light-bg-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$lighten-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$mark-bg-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$navbar-dark-active-bg # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$navbar-dark-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$navbar-dark-hover-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$navbar-dark-icon-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$navbar-dark-toggler-border-color # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$primary-bg-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$primary-bg-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$primary-border-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$primary-border-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$primary-text-emphasis # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$primary-text-emphasis-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$secondary-bg-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$secondary-bg-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$secondary-border-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$secondary-border-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$secondary-text-emphasis # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$secondary-text-emphasis-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$success-bg-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$success-bg-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$success-border-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$success-border-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$success-text-emphasis # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$success-text-emphasis-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$warning-bg-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$warning-bg-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$warning-border-subtle # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$warning-border-subtle-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$warning-text-emphasis # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
sass-type:$warning-text-emphasis-dark # accepted: documented exception of 1.6, the value follows --tblr-* overrides at runtime
|
||||
@@ -0,0 +1,14 @@
|
||||
# Compatibility fixture
|
||||
|
||||
A small project written the way a Tabler **1.5** user would write it. It must
|
||||
compile and behave the same on the last release from npm and on the working
|
||||
tree. `pnpm run check:compat-fixture` runs it against both.
|
||||
|
||||
- `project.scss` configures and reads 1.5 Sass variables, and calls 1.5
|
||||
functions and mixins.
|
||||
- `page.html` loads the compiled files from `dist/` with 1.5 markup, the
|
||||
libraries from `dist/libs`, and the old JavaScript helpers.
|
||||
|
||||
Do not update this project when Tabler changes. When a check fails, fix Tabler:
|
||||
see the `backward-compat` skill. Add to it only when a new kind of break shows
|
||||
that it missed something a real project does.
|
||||
@@ -0,0 +1,51 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Tabler 1.5 project</title>
|
||||
<link rel="stylesheet" href="/dist/css/tabler.css" />
|
||||
<link rel="stylesheet" href="/dist/css/tabler-vendors.css" />
|
||||
<style>
|
||||
.my-highlight {
|
||||
background-color: rgba(var(--tblr-primary-rgb), 0.5);
|
||||
}
|
||||
.my-button {
|
||||
--tblr-btn-focus-box-shadow: 0 0 0 4px rgb(255, 0, 0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div id="highlight" class="my-highlight">rgba() from the RGB triplet</div>
|
||||
<span id="legend" class="legend bg-primary"></span>
|
||||
<label class="form-label" for="email">Email</label>
|
||||
<input id="email" class="form-control" />
|
||||
<small id="hint" class="form-hint">We'll never share your email.</small>
|
||||
<button id="button" class="btn my-button" type="button">Focus me</button>
|
||||
<textarea id="message" class="form-control" data-bs-toggle="autosize" rows="1"></textarea>
|
||||
<h1 id="total" data-countup='{"duration":"0.2","enableScrollSpy":false}'>1500</h1>
|
||||
<input id="api-key" value="secret" />
|
||||
<button id="copy" class="btn" type="button" data-clipboard-target="#api-key">Copy</button>
|
||||
<input id="date" class="form-control" />
|
||||
<button id="open-modal" class="btn" type="button" data-bs-toggle="modal" data-bs-target="#modal">Open</button>
|
||||
<div class="modal" id="modal" tabindex="-1">
|
||||
<div class="modal-dialog"><div class="modal-content"><div class="modal-body">Hello</div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/dist/libs/autosize/dist/autosize.min.js"></script>
|
||||
<script src="/dist/libs/countup.js/dist/countUp.umd.js"></script>
|
||||
<script src="/dist/libs/clipboard/dist/clipboard.min.js"></script>
|
||||
<script src="/dist/libs/litepicker/dist/litepicker.js"></script>
|
||||
<script src="/dist/js/tabler.js"></script>
|
||||
<script>
|
||||
window.fixture = {
|
||||
clipboard: new ClipboardJS('#copy'),
|
||||
picker: new Litepicker({ element: document.getElementById('date'), inlineMode: true }),
|
||||
color: tabler.tabler.getColor('primary'),
|
||||
colorHalf: tabler.tabler.getColor('primary', 0.5),
|
||||
prefix: tabler.tabler.prefix,
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
// A 1.5 project that compiles Tabler from source. Every variable configured
|
||||
// here existed in 1.5; configuring one that is gone is a Sass compile error.
|
||||
@use 'scss/tabler' as tabler with (
|
||||
$input-btn-focus-width: 0.125rem,
|
||||
$input-btn-focus-color-opacity: 0.4,
|
||||
$btn-focus-box-shadow: 0 0 0 3px red,
|
||||
$form-hint-margin-top: 0.5rem,
|
||||
$form-switch-checked-bg-position: right center,
|
||||
$pagination-focus-outline: 0,
|
||||
$enable-deprecation-messages: false
|
||||
);
|
||||
|
||||
// Reading old variables and calling old helpers, as a project's own partials do.
|
||||
.fixture {
|
||||
--fixture-width: #{tabler.$input-focus-width};
|
||||
--fixture-primary-rgb: #{tabler.to-rgb(tabler.$primary)};
|
||||
--fixture-has-rgb-map: #{map-has-key(tabler.$theme-colors-rgb, 'primary')};
|
||||
color: tabler.theme-color-darker(#066fd1);
|
||||
background: tabler.theme-color-lighter(#066fd1);
|
||||
border-color: tabler.theme-color-lighter(tabler.$primary);
|
||||
background-image: tabler.url-svg('<svg viewBox="0 0 1 1"/>');
|
||||
transition-property: tabler.varify((a, b));
|
||||
|
||||
&:focus {
|
||||
@include tabler.focus-ring($show-border: true);
|
||||
}
|
||||
|
||||
@include tabler.media-breakpoint-down-than(md) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ export const cssVarIgnore = [
|
||||
/^--bs-/, // bootstrap
|
||||
/^--fc-/, // fullcalendar
|
||||
/^--gl-/, // star-rating.js
|
||||
/^--litepicker-/, // litepicker, deprecated(2.0) with `vendor/_litepicker.scss`
|
||||
/^--plyr-/, // plyr
|
||||
/^--ts-/, // tom-select
|
||||
'--section-bg', // marketing sections, unprefixed since it was introduced
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Downloads the last release of `@tabler/core` from npm, once, and returns where
|
||||
// it was unpacked. `check-compat` compares its public surface with the working
|
||||
// tree; `check-compat-fixture` runs a 1.5-style project against both.
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
|
||||
export const pkgName = '@tabler/core'
|
||||
const coreDir = 'core'
|
||||
const cacheDir = 'node_modules/.cache/check-compat'
|
||||
|
||||
const registry = 'https://registry.npmjs.org'
|
||||
|
||||
export async function releasedPackage(): Promise<{ dir: string; version: string }> {
|
||||
const local = JSON.parse(readFileSync(join(coreDir, 'package.json'), 'utf8')).version as string
|
||||
// On the versions PR the local version is not published yet: compare with `latest`.
|
||||
let version = local
|
||||
let response = await fetch(`${registry}/${pkgName}/${version}`)
|
||||
if (response.status === 404) {
|
||||
response = await fetch(`${registry}/${pkgName}/latest`)
|
||||
}
|
||||
if (!response.ok) throw new Error(`npm registry answered ${response.status} for ${pkgName}`)
|
||||
const manifest = (await response.json()) as { version: string; dist: { tarball: string } }
|
||||
version = manifest.version
|
||||
|
||||
const dir = join(cacheDir, version)
|
||||
if (!existsSync(join(dir, 'package', 'package.json'))) {
|
||||
mkdirSync(dir, { recursive: true })
|
||||
const tarball = await fetch(manifest.dist.tarball)
|
||||
if (!tarball.ok) throw new Error(`could not download ${manifest.dist.tarball}: ${tarball.status}`)
|
||||
const archive = join(dir, 'package.tgz')
|
||||
writeFileSync(archive, Buffer.from(await tarball.arrayBuffer()))
|
||||
execFileSync('tar', ['-xzf', archive, '-C', dir])
|
||||
}
|
||||
return { dir: join(dir, 'package'), version }
|
||||
}
|
||||
@@ -3,4 +3,4 @@
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Replaced the `autosize` package with a dependency-free `Autosize` component that fires `resized.bs.autosize`.
|
||||
Added a dependency-free `Autosize` component that fires `resized.bs.autosize`; `dist/libs/autosize` is deprecated.
|
||||
@@ -4,4 +4,4 @@
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added a `Clipboard` copy button and dropped the `clipboard` package; the browser API does the work.
|
||||
Added a `Clipboard` copy button built on the browser API; `dist/libs/clipboard` is deprecated.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Fixed `CountUp` rejecting numbers and booleans written as strings in `data-countup`, which countUp.js accepted.
|
||||
@@ -3,4 +3,4 @@
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Replaced the `countup.js` package with a dependency-free `CountUp` component that respects `prefers-reduced-motion`.
|
||||
Added a dependency-free `CountUp` component that respects `prefers-reduced-motion`; `dist/libs/countup.js` is deprecated.
|
||||
@@ -4,4 +4,4 @@
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Added `Datepicker` plugin built on Vanilla Calendar Pro with a `datepicker` preview page, and removed Litepicker from `dist/libs`.
|
||||
Added `Datepicker` plugin built on Vanilla Calendar Pro with a `datepicker` preview page; Litepicker is deprecated.
|
||||
@@ -3,4 +3,4 @@
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Updated the default gray scale (`$gray-50`…`$gray-950`) to `neutral`; the old one stays as `data-bs-theme-base="gray"`.
|
||||
Updated the default gray scale (`$gray-50`…`$gray-950`) to `neutral`; `data-bs-theme-base="gray"` keeps the 1.5 look.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Updated `theme-color-lighter()`, `url-svg()`, `varify()` and five more Sass helpers to deprecated; they warn when used.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Added `$enable-deprecated`; set it to `false` to leave the deprecated aliases and `--tblr-*-rgb` variables out of the CSS.
|
||||
@@ -2,5 +2,4 @@
|
||||
'@tabler/core': minor
|
||||
---
|
||||
|
||||
Changed the focus indicator from a `box-shadow` ring to an `outline`, following Bootstrap v6. `focus-ring($offset, $color)` is the single focus mixin, driven by the new `--focus-ring`, `--focus-ring-offset` and `--focus-ring-color` tokens. Removed the `$*-focus-box-shadow` Sass variables and the
|
||||
`--btn-focus-box-shadow`, `--pagination-focus-box-shadow`, `--accordion-btn-focus-box-shadow` and `--btn-close-focus-shadow` custom properties.
|
||||
Updated the focus indicator from a `box-shadow` to an `outline`; the `$*-focus-box-shadow` variables and tokens are deprecated.
|
||||
@@ -3,4 +3,4 @@
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Removed the `--tblr-*-rgb` variables and moved color mixing to `color-mix(in oklab)`; use `color-mix()` instead of `rgba(var(--tblr-*-rgb))`.
|
||||
Updated color mixing to `color-mix(in oklab)`; the `--tblr-*-rgb` variables are deprecated and stay until 2.0.
|
||||
@@ -3,4 +3,4 @@
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Updated the color palette to `oklch()`, masked the checkbox, switch, toggler and carousel icons, and removed the `tabler` JS namespace.
|
||||
Updated the palette to `oklch()` and masked the check, switch, toggler and carousel icons; `tabler` JS namespace is deprecated.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Added back the `tabler` JS namespace with `getColor()` and `hexToRgba()` as deprecated; `getColor()` handles `oklch()` colors.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@tabler/core": patch
|
||||
---
|
||||
|
||||
Added back the Sass variables, functions and mixin parameters removed since 1.5, as deprecated aliases until 2.0.
|
||||
@@ -2,4 +2,4 @@
|
||||
"@tabler/core": minor
|
||||
---
|
||||
|
||||
Added SortableJS drag styles and turned on `forceFallback` by default so `data-sortable` lists drag a styled, tilted copy.
|
||||
Added SortableJS drag styles; set `forceFallback` to `true` on a `data-sortable` list to drag a styled, tilted copy.
|
||||
@@ -31,3 +31,8 @@ jobs:
|
||||
|
||||
- name: Check markup classes
|
||||
run: pnpm run check:markup-classes --html preview/dist --html docs/dist --css preview/dist/dist/css --css preview/dist/dist/libs --css preview/dist/preview/css --css docs/dist/css --css docs/dist/preview/css
|
||||
|
||||
# A project written for the last release has to compile and behave the
|
||||
# same on this build. Runs here because it needs the core build and a browser.
|
||||
- name: Check a project written for the last release
|
||||
run: pnpm run check:compat-fixture
|
||||
+22
-1
@@ -83,6 +83,27 @@ const DefaultType: Record<keyof ComponentConfig, string> = {
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
// deprecated(2.0): countUp.js took `"duration":"3"` or `"useGrouping":"false"`
|
||||
// from `data-countup` without complaint. The typed config would reject them, so
|
||||
// attribute values that are plainly a number or a boolean are read as one.
|
||||
const coerceOptions = (options: Record<string, unknown>): Record<string, unknown> => {
|
||||
const result: Record<string, unknown> = { ...options }
|
||||
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
const expected = DefaultType[key as keyof ComponentConfig]
|
||||
|
||||
if (typeof value === 'string' && expected === 'number' && value.trim() !== '' && !Number.isNaN(Number(value))) {
|
||||
result[key] = Number(value)
|
||||
} else if (typeof value === 'string' && expected === 'boolean' && (value === 'true' || value === 'false')) {
|
||||
result[key] = value === 'true'
|
||||
} else if (typeof value === 'number' && expected === 'string') {
|
||||
result[key] = String(value)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Strips thousands separators, currency symbols and other non-numeric
|
||||
// characters, so formatted targets like "1,234", "1 234" or "$99.5" parse.
|
||||
// A `time` value like "3:28" is read as minutes.
|
||||
@@ -229,7 +250,7 @@ class CountUp extends BaseComponent {
|
||||
}
|
||||
}
|
||||
|
||||
return super._mergeConfigObj({ ...dataOptions, ...config }, element)
|
||||
return super._mergeConfigObj({ ...coerceOptions(dataOptions), ...config }, element)
|
||||
}
|
||||
|
||||
_animate(from: number, to: number): void {
|
||||
|
||||
@@ -30,9 +30,9 @@ const DATA_ATTRIBUTE = `data-${NAME}`
|
||||
|
||||
const SELECTOR_DATA_SORTABLE = `[${DATA_ATTRIBUTE}]`
|
||||
|
||||
const Default: ComponentConfig = {
|
||||
forceFallback: true,
|
||||
}
|
||||
// SortableJS defaults apply. Set `forceFallback: true` to drag an HTML copy that
|
||||
// `.sortable-drag` can style, instead of the browser's drag image.
|
||||
const Default: ComponentConfig = {}
|
||||
|
||||
const DefaultType: Record<string, string> = {}
|
||||
|
||||
@@ -42,7 +42,7 @@ const DefaultType: Record<string, string> = {}
|
||||
* Wraps SortableJS (https://sortablejs.github.io/Sortable/), loaded separately
|
||||
* as `window.Sortable`. Without the plugin the component is inert. Options come
|
||||
* from the `data-sortable` attribute as JSON, or from the config object.
|
||||
* `forceFallback` is on by default so the dragged copy can be styled with `.sortable-drag`.
|
||||
* Turn `forceFallback` on so the dragged copy can be styled with `.sortable-drag`.
|
||||
*/
|
||||
|
||||
class Sortable extends BaseComponent {
|
||||
|
||||
@@ -299,4 +299,22 @@ describe('CountUp', () => {
|
||||
expect(second).toBe(first)
|
||||
})
|
||||
})
|
||||
describe('loose data-countup types', () => {
|
||||
it('should read numbers and booleans written as strings, as countUp.js did', () => {
|
||||
fixtureEl.innerHTML = '<h1 data-countup=\'{"duration":"3","decimalPlaces":"2","useGrouping":"false","separator":1}\'>30000</h1>'
|
||||
|
||||
const instance = new CountUp(element())
|
||||
|
||||
expect(instance._config.duration).toBe(3)
|
||||
expect(instance._config.decimalPlaces).toBe(2)
|
||||
expect(instance._config.useGrouping).toBe(false)
|
||||
expect(instance._config.separator).toBe('1')
|
||||
})
|
||||
|
||||
it('should still reject a value that is not a number', () => {
|
||||
fixtureEl.innerHTML = '<h1 data-countup=\'{"duration":"fast"}\'>30000</h1>'
|
||||
|
||||
expect(() => new CountUp(element())).toThrow(TypeError)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -45,19 +45,19 @@ describe('Sortable', () => {
|
||||
expect(instance.sortable).toBe(plugin.mock.instances[0])
|
||||
})
|
||||
|
||||
it('should drag a styled copy by default', () => {
|
||||
it('should keep the SortableJS default for the drag image', () => {
|
||||
new Sortable(list())
|
||||
|
||||
expect(plugin.mock.calls[0][1]).not.toHaveProperty('forceFallback')
|
||||
})
|
||||
|
||||
it('should let data-sortable turn the styled copy on', () => {
|
||||
fixtureEl.innerHTML = '<ul data-sortable=\'{"forceFallback":true}\'><li>a</li></ul>'
|
||||
new Sortable(list())
|
||||
|
||||
expect(plugin.mock.calls[0][1]).toMatchObject({ forceFallback: true })
|
||||
})
|
||||
|
||||
it('should let data-sortable turn the styled copy off', () => {
|
||||
fixtureEl.innerHTML = '<ul data-sortable=\'{"forceFallback":false}\'><li>a</li></ul>'
|
||||
new Sortable(list())
|
||||
|
||||
expect(plugin.mock.calls[0][1]).toMatchObject({ forceFallback: false })
|
||||
})
|
||||
|
||||
it('should let the config object win over the attribute', () => {
|
||||
new Sortable(list(), { animation: 0, group: 'shared' })
|
||||
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
"npm": "imask",
|
||||
"js": ["dist/imask.min.js"]
|
||||
},
|
||||
"autosize": {
|
||||
"npm": "autosize",
|
||||
"js": ["dist/autosize.min.js"]
|
||||
},
|
||||
"clipboard": {
|
||||
"npm": "clipboard",
|
||||
"js": ["dist/clipboard.min.js"]
|
||||
},
|
||||
"countup": {
|
||||
"npm": "countup.js",
|
||||
"js": ["dist/countUp.umd.js"]
|
||||
},
|
||||
"litepicker": {
|
||||
"npm": "litepicker",
|
||||
"js": ["dist/litepicker.js"]
|
||||
},
|
||||
"apexcharts": {
|
||||
"npm": "apexcharts",
|
||||
"js": ["dist/apexcharts.min.js"]
|
||||
|
||||
+8
-4
@@ -82,19 +82,19 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "./dist/css/tabler.css",
|
||||
"maxSize": "88 kB"
|
||||
"maxSize": "90 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler.min.css",
|
||||
"maxSize": "82 kB"
|
||||
"maxSize": "84 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler.rtl.css",
|
||||
"maxSize": "88 kB"
|
||||
"maxSize": "90 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler.rtl.min.css",
|
||||
"maxSize": "82 kB"
|
||||
"maxSize": "84 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/css/tabler-flags.css",
|
||||
@@ -259,7 +259,10 @@
|
||||
"@vitest/browser-playwright": "4.1.11",
|
||||
"@vitest/coverage-istanbul": "4.1.11",
|
||||
"apexcharts": "7.0.0",
|
||||
"autosize": "^6.0.1",
|
||||
"choices.js": "^11.2.4",
|
||||
"clipboard": "^2.0.11",
|
||||
"countup.js": "^2.10.1",
|
||||
"driver.js": "^1.8.0",
|
||||
"dropzone": "^6.0.0-beta.2",
|
||||
"find-unused-sass-variables": "^6.2.1",
|
||||
@@ -270,6 +273,7 @@
|
||||
"imask": "^7.6.1",
|
||||
"jsvectormap": "^1.7.0",
|
||||
"list.js": "^2.3.1",
|
||||
"litepicker": "^2.0.12",
|
||||
"nouislider": "^15.8.1",
|
||||
"playwright": "1.62.1",
|
||||
"plyr": "^3.8.4",
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// The `--tblr-*-rgb` custom properties of older 1.x releases, as mixins: three
|
||||
// bundles emit them (`tabler.css`, `tabler-props.css`, `tabler-themes.css`), so
|
||||
// this module emits nothing on its own. See `_deprecated.scss` for the rest.
|
||||
//
|
||||
// Removed in 2.0, together with this file.
|
||||
@use 'sass:color';
|
||||
@use 'sass:map';
|
||||
@use 'sass:math';
|
||||
@use 'config' as *;
|
||||
|
||||
// `6, 111, 209`: whole numbers, as the 1.5 stylesheet had them.
|
||||
@function deprecated-rgb-triplet($color) {
|
||||
$rgb: color.to-gamut($color, $space: rgb, $method: clip);
|
||||
@return math.round(color.channel($rgb, 'red', $space: rgb)), math.round(color.channel($rgb, 'green', $space: rgb)), math.round(color.channel($rgb, 'blue', $space: rgb));
|
||||
}
|
||||
|
||||
// deprecated(2.0): `--tblr-*-rgb`. Tabler mixes colours with `color-mix()` and
|
||||
// reads none of these. They are static, as they were in 1.5: overriding
|
||||
// `--tblr-primary` does not change `--tblr-primary-rgb`.
|
||||
@mixin deprecated-color-props() {
|
||||
@if $enable-deprecated {
|
||||
:root {
|
||||
@each $name, $color in map.merge($theme-colors, $social-colors) {
|
||||
--#{$name}-rgb: #{deprecated-rgb-triplet($color)};
|
||||
--#{$name}-lt-rgb: #{deprecated-rgb-triplet(color.mix($color, #fff, 10%, $method: rgb))};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin deprecated-theme-props() {
|
||||
@if $enable-deprecated {
|
||||
@each $name, $value in $extra-colors {
|
||||
[data-bs-theme-primary='#{$name}'],
|
||||
[data-theme-primary='#{$name}'] {
|
||||
--primary-rgb: #{deprecated-rgb-triplet($value)};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
// CSS kept only so that projects written for an older 1.x release keep working:
|
||||
// class aliases, custom properties that nothing in Tabler reads any more, and
|
||||
// hooks that still honour the old tokens. Set `$enable-deprecated: false` to
|
||||
// leave all of it out of the build.
|
||||
//
|
||||
// Loaded last from `tabler.scss`, after `_extends.scss`: the aliases are built
|
||||
// with `@extend`, which only reaches modules upstream of this one.
|
||||
//
|
||||
// Removed in 2.0, together with this file and `_deprecated-props.scss`.
|
||||
@use 'sass:map';
|
||||
@use 'config' as *;
|
||||
@use 'core';
|
||||
@use 'deprecated-props' as *;
|
||||
|
||||
@if $enable-deprecated {
|
||||
@include deprecated-color-props();
|
||||
|
||||
:root {
|
||||
--white-rgb: #{deprecated-rgb-triplet($white)};
|
||||
--black-rgb: #{deprecated-rgb-triplet($black)};
|
||||
--body-color-rgb: #{deprecated-rgb-triplet($body-color)};
|
||||
--body-bg-rgb: #{deprecated-rgb-triplet($body-bg)};
|
||||
--emphasis-color-rgb: #{deprecated-rgb-triplet($body-emphasis-color)};
|
||||
--secondary-color-rgb: #{deprecated-rgb-triplet($body-color)};
|
||||
--secondary-bg-rgb: #{deprecated-rgb-triplet($body-secondary-bg)};
|
||||
--tertiary-color-rgb: #{deprecated-rgb-triplet($body-color)};
|
||||
--tertiary-bg-rgb: #{deprecated-rgb-triplet($body-tertiary-bg)};
|
||||
--link-color-rgb: #{deprecated-rgb-triplet($link-color)};
|
||||
--link-hover-color-rgb: #{deprecated-rgb-triplet($link-hover-color)};
|
||||
|
||||
// deprecated(2.0): `$input-btn-focus-width` and `$input-btn-focus-color`
|
||||
// were the way to restyle the focus ring from Sass
|
||||
@if $input-btn-focus-width != 0.25rem {
|
||||
--focus-ring-width: #{$input-btn-focus-width};
|
||||
}
|
||||
@if $input-btn-focus-color != color-transparent(var(--primary), $input-btn-focus-color-opacity) {
|
||||
--focus-ring-color: #{$input-btn-focus-color};
|
||||
}
|
||||
}
|
||||
|
||||
@if $enable-dark-mode {
|
||||
@include color-mode(dark, true) {
|
||||
--body-color-rgb: #{deprecated-rgb-triplet($body-color-dark)};
|
||||
--body-bg-rgb: #{deprecated-rgb-triplet($body-bg-dark)};
|
||||
--emphasis-color-rgb: #{deprecated-rgb-triplet($body-emphasis-color-dark)};
|
||||
--secondary-color-rgb: #{deprecated-rgb-triplet($body-color-dark)};
|
||||
--secondary-bg-rgb: #{deprecated-rgb-triplet($body-secondary-bg-dark)};
|
||||
--tertiary-color-rgb: #{deprecated-rgb-triplet($body-color-dark)};
|
||||
--tertiary-bg-rgb: #{deprecated-rgb-triplet($body-tertiary-bg-dark)};
|
||||
--link-color-rgb: #{deprecated-rgb-triplet($link-color-dark)};
|
||||
--link-hover-color-rgb: #{deprecated-rgb-triplet($link-hover-color-dark)};
|
||||
}
|
||||
}
|
||||
|
||||
// `.form-hint` is deprecated, use `.form-text` instead
|
||||
// (from `bootstrap/forms/_form-text.scss`).
|
||||
.form-hint {
|
||||
@extend .form-text;
|
||||
--form-hint-margin-top: #{$form-hint-margin-top};
|
||||
--form-hint-label-offset: #{$form-hint-label-offset};
|
||||
--form-hint-control-margin-top: #{$form-hint-control-margin-top};
|
||||
|
||||
// Kept from the old rule, so an inline element still gets the top margin.
|
||||
display: block;
|
||||
|
||||
+ .form-control {
|
||||
margin-top: var(--form-hint-margin-top);
|
||||
}
|
||||
|
||||
.form-label + & {
|
||||
margin-top: var(--form-hint-label-offset);
|
||||
}
|
||||
|
||||
.input-group + &,
|
||||
.form-control + &,
|
||||
.form-select + & {
|
||||
margin-top: var(--form-hint-control-margin-top);
|
||||
}
|
||||
}
|
||||
|
||||
// Before 1.6 `.legend` was the dot itself and had no children. An empty
|
||||
// `.legend` is deprecated, use `.legend-dot` instead (from `ui/_legend.scss`).
|
||||
.legend:empty {
|
||||
@extend .legend-dot;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// deprecated(2.0): `--tblr-status-color-rgb`, use `--tblr-status-color`
|
||||
.status {
|
||||
--status-color-rgb: #{deprecated-rgb-triplet($text-secondary)};
|
||||
}
|
||||
|
||||
@each $name, $color in map.merge($theme-colors, $social-colors) {
|
||||
.status-#{$name} {
|
||||
--status-color-rgb: var(--#{$name}-rgb);
|
||||
}
|
||||
}
|
||||
|
||||
// deprecated(2.0): the focus ring is an outline. A project that set one of
|
||||
// the old box-shadow tokens still gets its shadow, next to the outline.
|
||||
// A button has a shadow of its own, so the fallback is that one and an
|
||||
// untouched project looks the same. `.btn-link` sets `box-shadow: none`
|
||||
// directly and needs its own fallback.
|
||||
.btn:focus-visible:not(:active),
|
||||
.btn-check:focus-visible + .btn {
|
||||
@if $btn-focus-box-shadow != $focus-ring-box-shadow {
|
||||
--btn-focus-box-shadow: #{$btn-focus-box-shadow};
|
||||
}
|
||||
box-shadow: var(--btn-focus-box-shadow, var(--btn-box-shadow));
|
||||
}
|
||||
|
||||
.btn-link:focus-visible:not(:active) {
|
||||
box-shadow: var(--btn-focus-box-shadow, none);
|
||||
}
|
||||
|
||||
.btn-close:focus-visible {
|
||||
@if $btn-close-focus-shadow != $focus-ring-box-shadow {
|
||||
--btn-close-focus-shadow: #{$btn-close-focus-shadow};
|
||||
}
|
||||
box-shadow: var(--btn-close-focus-shadow, none);
|
||||
}
|
||||
|
||||
.page-link:focus-visible {
|
||||
@if $pagination-focus-box-shadow != $focus-ring-box-shadow {
|
||||
--pagination-focus-box-shadow: #{$pagination-focus-box-shadow};
|
||||
}
|
||||
box-shadow: var(--pagination-focus-box-shadow, none);
|
||||
}
|
||||
|
||||
.accordion-button:focus-visible {
|
||||
@if $accordion-btn-focus-box-shadow != $focus-ring-box-shadow {
|
||||
--accordion-btn-focus-box-shadow: #{$accordion-btn-focus-box-shadow};
|
||||
}
|
||||
box-shadow: var(--accordion-btn-focus-box-shadow, none);
|
||||
}
|
||||
|
||||
// deprecated(2.0): `--tblr-focus-ring-x`, `-y` and `-blur` moved and blurred
|
||||
// the `.focus-ring` helper's shadow. All three default to `0`, which draws nothing.
|
||||
.focus-ring:focus-visible {
|
||||
box-shadow: var(--focus-ring-x, 0) var(--focus-ring-y, 0) var(--focus-ring-blur, 0) 0 var(--focus-ring-color);
|
||||
}
|
||||
|
||||
// deprecated(2.0): the check mark and the switch knob are masks now. An
|
||||
// image set through the old token is still painted, under the mask.
|
||||
.form-check-input:checked,
|
||||
.form-check-input:indeterminate {
|
||||
background-image: var(--form-check-bg-image, none);
|
||||
}
|
||||
|
||||
.form-switch .form-check-input {
|
||||
background-image: var(--form-switch-bg, none);
|
||||
}
|
||||
}
|
||||
@@ -102,19 +102,3 @@
|
||||
@extend [data-bs-theme='dark'];
|
||||
}
|
||||
}
|
||||
|
||||
// `.form-hint` is deprecated, use `.form-text` instead
|
||||
// (from `bootstrap/forms/_form-text.scss`).
|
||||
.form-hint {
|
||||
@extend .form-text;
|
||||
|
||||
// Kept from the old rule, so an inline element still gets the top margin.
|
||||
display: block;
|
||||
}
|
||||
|
||||
// Before 1.6 `.legend` was the dot itself and had no children. An empty
|
||||
// `.legend` is deprecated, use `.legend-dot` instead (from `ui/_legend.scss`).
|
||||
.legend:empty {
|
||||
@extend .legend-dot;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -25,6 +25,7 @@ $enable-container-classes: true !default;
|
||||
$enable-button-pointers: true !default;
|
||||
$enable-validation-icons: true !default;
|
||||
$enable-deprecation-messages: true !default;
|
||||
$enable-deprecated: true !default;
|
||||
$enable-important-utilities: true !default;
|
||||
|
||||
// Escaped Characters
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
// deprecated(2.0): use `mix-color($color, $background, 10%)`
|
||||
@function theme-color-lighter($color, $background: #fff) {
|
||||
$warned: -deprecated('theme-color-lighter()', 'Use mix-color() instead.');
|
||||
@return color.mix($color, $background, 10%);
|
||||
@return color.to-gamut(color.mix($color, $background, 10%, $method: rgb), $space: rgb, $method: clip);
|
||||
}
|
||||
|
||||
// deprecated(2.0): use `shade-color($color, 10%)`
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
@use 'deprecated-props' as *;
|
||||
|
||||
@forward 'props';
|
||||
|
||||
// `--tblr-*-rgb` of older 1.x releases, behind `$enable-deprecated`.
|
||||
@include deprecated-color-props();
|
||||
@@ -1,4 +1,5 @@
|
||||
@use 'config' as *;
|
||||
@use 'deprecated-props' as *;
|
||||
|
||||
[data-bs-theme-base='slate'],
|
||||
[data-theme-base='slate'] {
|
||||
@@ -129,3 +130,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `--tblr-primary-rgb` of older 1.x releases, behind `$enable-deprecated`.
|
||||
@include deprecated-theme-props();
|
||||
@@ -12,3 +12,6 @@
|
||||
@forward 'vendor/coloris';
|
||||
@forward 'vendor/typed';
|
||||
@forward 'vendor/fullcalendar';
|
||||
// deprecated(2.0): Litepicker is replaced by the Datepicker plugin; its styles
|
||||
// stay for projects that still load it.
|
||||
@forward 'vendor/litepicker';
|
||||
@@ -1,3 +1,5 @@
|
||||
@forward 'core';
|
||||
// Cross-module `@extend` rules — must load last, see the note in `_extends.scss`.
|
||||
@forward 'extends';
|
||||
// Aliases and tokens of older 1.x releases, behind `$enable-deprecated`.
|
||||
@forward 'deprecated';
|
||||
@@ -21,10 +21,24 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre
|
||||
"--gl-star-color",
|
||||
"--gl-star-color-inactive",
|
||||
"--gl-star-size",
|
||||
"--litepicker-button-next-month-color",
|
||||
"--litepicker-button-next-month-color-hover",
|
||||
"--litepicker-button-prev-month-color",
|
||||
"--litepicker-button-prev-month-color-hover",
|
||||
"--litepicker-container-months-color-bg",
|
||||
"--litepicker-day-color",
|
||||
"--litepicker-day-color-hover",
|
||||
"--litepicker-is-end-color-bg",
|
||||
"--litepicker-is-in-range-color",
|
||||
"--litepicker-is-start-color-bg",
|
||||
"--litepicker-is-today-color",
|
||||
"--litepicker-month-header-color",
|
||||
"--litepicker-month-weekday-color",
|
||||
"--plyr-color-main",
|
||||
"--tblr-active-bg",
|
||||
"--tblr-azure",
|
||||
"--tblr-backdrop-bg",
|
||||
"--tblr-bg-forms",
|
||||
"--tblr-bg-surface",
|
||||
"--tblr-bg-surface-inverted",
|
||||
"--tblr-bg-surface-secondary",
|
||||
@@ -61,6 +75,8 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre
|
||||
"--tblr-gray-500",
|
||||
"--tblr-green",
|
||||
"--tblr-icon-size",
|
||||
"--tblr-info",
|
||||
"--tblr-light",
|
||||
"--tblr-orange",
|
||||
"--tblr-primary",
|
||||
"--tblr-primary-200",
|
||||
|
||||
Vendored
+70
@@ -0,0 +1,70 @@
|
||||
@use '../config' as *;
|
||||
|
||||
.litepicker {
|
||||
--litepicker-month-weekday-color: #{var(--secondary)};
|
||||
--litepicker-button-prev-month-color: #{var(--secondary)};
|
||||
--litepicker-button-next-month-color: #{var(--secondary)};
|
||||
--litepicker-button-prev-month-color-hover: #{var(--primary)};
|
||||
--litepicker-button-next-month-color-hover: #{var(--primary)};
|
||||
--litepicker-day-color: var(--body-color);
|
||||
--litepicker-day-color-hover: #{var(--primary)};
|
||||
--litepicker-is-start-color-bg: #{var(--primary)};
|
||||
--litepicker-is-end-color-bg: #{var(--primary)};
|
||||
--litepicker-is-in-range-color: #{var(--info)};
|
||||
--litepicker-is-today-color: #{var(--primary)};
|
||||
--litepicker-month-header-color: var(--body-color);
|
||||
--litepicker-container-months-color-bg: var(--bg-surface);
|
||||
font: inherit;
|
||||
user-select: none;
|
||||
|
||||
.day-item.is-in-range {
|
||||
--litepicker-day-color: var(--light);
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: none !important;
|
||||
}
|
||||
|
||||
.container__main {
|
||||
border: var(--border-width) var(--border-style) var(--border-color);
|
||||
@include border-radius(var(--border-radius));
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.container__months {
|
||||
.month-item-name,
|
||||
.month-item-year {
|
||||
font-weight: var(--font-weight-medium) !important;
|
||||
}
|
||||
|
||||
.button-next-month,
|
||||
.button-previous-month {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.month-item-weekdays-row {
|
||||
> div {
|
||||
padding: 0.5rem 0 !important;
|
||||
font-size: $h5-font-size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container__days {
|
||||
.day-item {
|
||||
padding: 0.5rem 0 !important;
|
||||
cursor: pointer !important;
|
||||
@include transition(color $transition-time, background-color $transition-time, border-color $transition-time);
|
||||
}
|
||||
}
|
||||
|
||||
.datepicker-inline & {
|
||||
box-shadow: $input-box-shadow;
|
||||
|
||||
.container__months {
|
||||
background-color: var(--bg-forms);
|
||||
box-shadow: none;
|
||||
@include border-radius(calc(var(--border-radius) - 1px));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ Tabler includes a small script, [`tabler-theme.js`](https://github.com/tabler/ta
|
||||
| Setting | Attribute | Default | Allowed values |
|
||||
| --- | --- | --- | --- |
|
||||
| Color mode | `data-bs-theme` | `auto` | `light`, `dark`, `auto` |
|
||||
| Base gray shade | `data-bs-theme-base` | `gray` | `slate`, `gray`, `zinc`, `neutral`, `stone` |
|
||||
| Base gray shade | `data-bs-theme-base` | `neutral` | `slate`, `gray`, `zinc`, `neutral`, `stone` |
|
||||
| Font family | `data-bs-theme-font` | `sans-serif` | `sans-serif`, `serif`, `monospace`, `comic` |
|
||||
| Primary color | `data-bs-theme-primary` | `blue` | `blue`, `azure`, `indigo`, `purple`, `pink`, `red`, `orange`, `yellow`, `lime`, `green`, `teal`, `cyan`, `inverted` |
|
||||
| Corner radius | `data-bs-theme-radius` | `1` | `0`, `0.5`, `1`, `1.5`, `2` |
|
||||
|
||||
@@ -88,7 +88,7 @@ If you need a transparent version of a Tabler color in your own CSS, use `color-
|
||||
}
|
||||
```
|
||||
|
||||
The `--tblr-*-rgb` variables (for example `--tblr-primary-rgb: 6, 111, 209`) are no longer emitted. Replace any `rgba(var(--tblr-primary-rgb), 0.5)` in your own CSS with `color-mix(in oklab, var(--tblr-primary) 50%, transparent)`.
|
||||
The `--tblr-*-rgb` variables (for example `--tblr-primary-rgb: 6, 111, 209`) are deprecated. They are still emitted, but they are static: they don't follow an override of `--tblr-primary`, and they go away in 2.0. Replace `rgba(var(--tblr-primary-rgb), 0.5)` in your own CSS with `color-mix(in oklab, var(--tblr-primary) 50%, transparent)`.
|
||||
|
||||
## Other system colors
|
||||
|
||||
|
||||
@@ -1,40 +1,38 @@
|
||||
---
|
||||
title: Upgrade to 1.6
|
||||
summary: Move a project from Tabler 1.5 to 1.6. The breaking changes are listed with a before and after example for CSS, JavaScript and Sass.
|
||||
description: Upgrade guide from Tabler 1.5 to 1.6 with all breaking changes, removed color variables, the new JavaScript components and Sass updates.
|
||||
summary: Move a project from Tabler 1.5 to 1.6. Nothing breaks. The page lists what is deprecated, with a before and after example for CSS, JavaScript and Sass.
|
||||
description: Upgrade guide from Tabler 1.5 to 1.6 with every deprecated class, color variable, Sass variable and JavaScript helper, and what to use instead.
|
||||
added-in: '1.6.0'
|
||||
order: 1
|
||||
related: [/ui/getting-started/upgrade/1-5, /ui/getting-started/customize]
|
||||
---
|
||||
|
||||
Tabler 1.6 is a much smaller step than 1.5 was. If you only load the compiled files from `dist/`, the upgrade usually takes a few minutes. There are four things that can bite you, and they all live in your own code, not in Tabler's: any `rgba(var(--tblr-*-rgb), …)` in your CSS, any call to the old `autosize()`, `countUp`, `ClipboardJS` or `Litepicker` globals, any use of `tabler.tabler.getColor()`, and any `.legend` used as a colored dot.
|
||||
Tabler 1.6 is a drop-in update. A project that works on 1.5 works on 1.6 without a change: every class, custom property, Sass variable, function and file that 1.5 had is still there.
|
||||
|
||||
Projects that compile Tabler from the Sass sources should also read [Sass changes](#sass-changes).
|
||||
Some of them are **deprecated**. They keep working in every 1.x release and go away in 2.0. This page lists them with the replacement, so you can move over when it suits you. Sass warns about a deprecated function when you compile; set `$enable-deprecation-messages: false` to silence it.
|
||||
|
||||
There is one thing to check if you compile Tabler from the Sass sources and run Sass color functions on Tabler's variables: see [Variables that turned into color-mix()](#variables-that-turned-into-color-mix).
|
||||
|
||||
If you're coming from 1.4 or older, do the [1.5 upgrade](/ui/getting-started/upgrade/1-5) first.
|
||||
|
||||
## Overview
|
||||
|
||||
Use this table to find the changes that affect you.
|
||||
Nothing in this table is required. Use it to find what you can modernize.
|
||||
|
||||
If you…|You need to…
|
||||
If you…|You can…
|
||||
---|---
|
||||
Use `--tblr-primary-rgb` or any `--tblr-*-rgb` variable|Replace it with `color-mix()`, see [Color variables](#rgb-color-variables-are-gone)
|
||||
Use `--tblr-primary-rgb` or any `--tblr-*-rgb` variable|Switch to `color-mix()`, see [RGB color variables](#rgb-color-variables-are-deprecated)
|
||||
Load `dist/libs/autosize` or `dist/libs/countup.js`|Remove the script tags, both are part of `tabler.js` now
|
||||
Call `autosize(el)` or `new countUp.CountUp(...)` yourself|Switch to `tabler.Autosize` and `tabler.CountUp`
|
||||
Load `dist/libs/clipboard` or call `new ClipboardJS(...)`|Switch to the `Clipboard` component, see [Clipboard](#clipboard-is-built-in)
|
||||
Load `dist/libs/litepicker` or call `new Litepicker(...)`|Switch to the `Datepicker` plugin, see [Litepicker is replaced by Datepicker](#litepicker-is-replaced-by-datepicker)
|
||||
Use `<span class="legend">` as a colored dot|Rename to `.legend-dot` (the old markup still works), see [Legend is a component now](#legend-is-a-component-now)
|
||||
Want the 1.5 grays back|Load `tabler-themes.css` and set `data-bs-theme-base="gray"`, see [The default gray is neutral](#the-default-gray-is-neutral)
|
||||
Use `data-sortable`|Dragging looks different, see [Sortable drags a styled copy](#sortable-drags-a-styled-copy)
|
||||
Hide `path:first-child` in `.accordion-button-toggle-plus` from your own CSS|Drop that rule, see [Visual changes](#visual-changes)
|
||||
Call `tabler.tabler.getColor()` or `tabler.tabler.hexToRgba()`|Read the variable yourself, see [Removed JavaScript helpers](#removed-javascript-helpers)
|
||||
Use `.form-hint`|Rename to `.form-text` (the old name still works)
|
||||
Load `dist/libs/litepicker` or call `new Litepicker(...)`|Switch to the `Datepicker` plugin, see [Datepicker replaces Litepicker](#datepicker-replaces-litepicker)
|
||||
Use `<span class="legend">` as a colored dot|Rename to `.legend-dot`, see [Legend is a component now](#legend-is-a-component-now)
|
||||
Use `.form-hint`|Rename to `.form-text`, see [Form hint is form text](#form-hint-is-form-text)
|
||||
Call `tabler.tabler.getColor()` or `tabler.tabler.hexToRgba()`|Read the variable yourself, see [Deprecated JavaScript helpers](#deprecated-javascript-helpers)
|
||||
Override `$form-switch-bg-image` or the toggler icon variables|See [Masked icons](#masked-icons)
|
||||
Override `$input-btn-focus-*`, a `$*-focus-box-shadow` variable or `--tblr-btn-focus-box-shadow`|Use the focus ring tokens, see [The focus ring is an outline](#the-focus-ring-is-an-outline)
|
||||
Override `$theme-colors-rgb` or use `theme-color-lighter()`|See [Sass changes](#sass-changes)
|
||||
Rely on the empty gutter next to the scrollbar|See [Visual changes](#visual-changes)
|
||||
Set `data-mask` or `data-countup` from code after page load|Create the component instead, see [Plugins are components now](#plugins-are-components-now)
|
||||
Use `theme-color-lighter()` or another function from the [list below](#deprecated-functions)|Switch to the replacement
|
||||
Ship your own build and want the smallest CSS|Set `$enable-deprecated: false`, see [Dropping the deprecated layer](#dropping-the-deprecated-layer)
|
||||
|
||||
## Update the package
|
||||
|
||||
@@ -54,31 +52,29 @@ Or update the CDN links:
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@1.6.0/dist/js/tabler.min.js"></script>
|
||||
```
|
||||
|
||||
## RGB color variables are gone
|
||||
## RGB color variables are deprecated
|
||||
|
||||
This is the change most likely to affect a custom stylesheet.
|
||||
|
||||
Tabler used to emit an RGB triplet next to every color, so you could build a transparent version with `rgba()`:
|
||||
Tabler emits an RGB triplet next to every color, so you can build a transparent version with `rgba()`:
|
||||
|
||||
```css
|
||||
/* 1.5 */
|
||||
/* works in 1.5 and 1.6 */
|
||||
.my-highlight {
|
||||
background-color: rgba(var(--tblr-primary-rgb), 0.2);
|
||||
}
|
||||
```
|
||||
|
||||
Those `--tblr-*-rgb` variables (and `--tblr-*-lt-rgb`) aren't emitted any more. Tabler mixes its own tints, shades and translucent surfaces at runtime with `color-mix()`, and your CSS can do the same:
|
||||
Tabler itself no longer reads the `--tblr-*-rgb` and `--tblr-*-lt-rgb` variables. It mixes its tints, shades and translucent surfaces at runtime with `color-mix()`, and your CSS can do the same:
|
||||
|
||||
```css
|
||||
/* 1.6 */
|
||||
/* 1.6 and later */
|
||||
.my-highlight {
|
||||
background-color: color-mix(in oklab, var(--tblr-primary) 20%, transparent);
|
||||
}
|
||||
```
|
||||
|
||||
A quick way to find every place that needs a change is to grep your project for `-rgb)`.
|
||||
The triplets are still emitted, with the same values, and are removed in 2.0. To find every place to move over, grep your project for `-rgb)`.
|
||||
|
||||
There's a nice side effect. Because everything is derived from `--tblr-primary` at runtime, overriding that one variable is enough to recolor the whole theme. In 1.5 you also had to set `--tblr-primary-rgb` by hand, or hover states and focus rings would keep the old color. That step is gone:
|
||||
There's a good reason to switch. The triplets are static: overriding `--tblr-primary` does not change `--tblr-primary-rgb`, so in 1.5 you had to set both. Everything Tabler derives from `--tblr-primary` now follows it, so one variable recolors the whole theme:
|
||||
|
||||
```diff
|
||||
:root {
|
||||
@@ -87,11 +83,11 @@ There's a nice side effect. Because everything is derived from `--tblr-primary`
|
||||
}
|
||||
```
|
||||
|
||||
`--tblr-primary-lt`, `--tblr-primary-darken` and the other derived variables still exist, they're just computed with `color-mix()` now.
|
||||
`--tblr-primary-lt`, `--tblr-primary-darken` and the other derived variables still exist, they're computed with `color-mix()` now.
|
||||
|
||||
### The palette is defined in oklch
|
||||
|
||||
The color values themselves moved from hex to `oklch()`. `--tblr-primary` used to resolve to `#066fd1`, now it resolves to `oklch(54.6% 0.1724 254.2deg)`. The colors look the same. It only matters if you read a variable from JavaScript and expect a hex string, see [Removed JavaScript helpers](#removed-javascript-helpers) below.
|
||||
The color values themselves moved from hex to `oklch()`. `--tblr-primary` used to resolve to `#066fd1`, now it resolves to `oklch(54.6% 0.1724 254.2deg)`. The colors look the same. It only matters if you read a variable from JavaScript and expect a hex string, see [Deprecated JavaScript helpers](#deprecated-javascript-helpers) below.
|
||||
|
||||
Every browser that could run Tabler 1.5 supports `oklch()`, so the [minimum versions](/ui/getting-started/browser-support) don't change.
|
||||
|
||||
@@ -107,11 +103,11 @@ Component|Attribute|Docs
|
||||
`tabler.Sortable`|`data-sortable`|[Sortable](/ui/plugins/sortable)
|
||||
`tabler.SwitchIcon`|`data-bs-toggle="switch-icon"`|[Switch icon](/ui/components/switch-icon)
|
||||
|
||||
Markup with data attributes keeps working as it did. Tabler still finds every element on page load and creates the component for it. What changes is the JavaScript side.
|
||||
Markup with data attributes keeps working as it did. Tabler still finds every element on page load and creates the component for it.
|
||||
|
||||
### Autosize and countUp.js are bundled
|
||||
### Autosize and countUp.js are built in
|
||||
|
||||
Tabler no longer depends on the `autosize` and `countup.js` packages. Both were rewritten inside `tabler.js`, so they don't need a separate script and don't exist in `dist/libs` any more. Remove them from your pages:
|
||||
Both were rewritten inside `tabler.js`, so they don't need a separate script. The old files stay in `dist/libs` until 2.0, so a page that loads them keeps working, but you can remove them:
|
||||
|
||||
```diff
|
||||
- <script src="/dist/libs/autosize/dist/autosize.min.js"></script>
|
||||
@@ -125,7 +121,7 @@ And from your dependencies, if you installed them for Tabler:
|
||||
npm uninstall autosize countup.js
|
||||
```
|
||||
|
||||
If you called the libraries directly for elements added later, switch to the components:
|
||||
If you called the libraries directly for elements added later, the components do the same:
|
||||
|
||||
```diff
|
||||
- autosize(document.getElementById('message'));
|
||||
@@ -140,24 +136,15 @@ If you called the libraries directly for elements added later, switch to the com
|
||||
|
||||
The `CountUp` component reads the target number from the element's text, like the `data-countup` attribute always did. It respects `prefers-reduced-motion` on its own, so you can drop the workaround from the 1.5 docs that removed `data-countup` for those users.
|
||||
|
||||
Options you passed to countUp.js in `data-countup` keep their names: `startVal`, `duration`, `decimalPlaces`, `useEasing`, `useGrouping`, `separator`, `decimal`, `prefix` and `suffix`. Anything outside that list is ignored.
|
||||
Options you passed to countUp.js in `data-countup` keep their names: `startVal`, `duration`, `decimalPlaces`, `useEasing`, `useGrouping`, `separator`, `decimal`, `prefix` and `suffix`. A number or a boolean written as a string, such as `"duration":"3"`, is still read. Anything outside that list is ignored.
|
||||
|
||||
### IMask and SortableJS stay external
|
||||
|
||||
`InputMask` and `Sortable` are thin wrappers, so you still install [IMask](/ui/plugins/input-mask) and [SortableJS](/ui/plugins/sortable) yourself and load them before `tabler.js`. Nothing changes there. What's new is that the component keeps a reference to the library instance, so you can reach it from `getInstance()` instead of keeping your own.
|
||||
|
||||
#### Sortable drags a styled copy
|
||||
|
||||
The `Sortable` component now turns on the SortableJS `forceFallback` option. A dragged item is an HTML copy that Tabler styles with `.sortable-drag`, instead of the browser's own drag image. Turn the option off on a list to get the 1.5 behavior back:
|
||||
|
||||
```diff
|
||||
- <ul class="list-group" data-sortable>
|
||||
+ <ul class="list-group" data-sortable='{"forceFallback":false}'>
|
||||
```
|
||||
|
||||
### Clipboard is built in
|
||||
|
||||
The `clipboard` package is gone from the dependencies and from `dist/libs`. A page that loads `dist/libs/clipboard/dist/clipboard.min.js` gets a 404 after the upgrade. Tabler has its own [Clipboard](/ui/plugins/clipboard) component now, written on top of the browser's `navigator.clipboard` API, so there is nothing to load:
|
||||
Tabler has its own [Clipboard](/ui/plugins/clipboard) component, written on top of the browser's `navigator.clipboard` API. `dist/libs/clipboard` stays in the package until 2.0, so code that uses ClipboardJS keeps working. To move over, drop the script:
|
||||
|
||||
```diff
|
||||
- <script src="/dist/libs/clipboard/dist/clipboard.min.js"></script>
|
||||
@@ -168,7 +155,7 @@ The `clipboard` package is gone from the dependencies and from `dist/libs`. A pa
|
||||
npm uninstall clipboard
|
||||
```
|
||||
|
||||
The markup changes too. A copy button carries `data-bs-toggle="clipboard"` and points at its source with `data-bs-target` or `data-bs-text`, and the two states live in the button:
|
||||
A copy button carries `data-bs-toggle="clipboard"` and points at its source with `data-bs-target` or `data-bs-text`, and the two states live in the button:
|
||||
|
||||
```diff
|
||||
- <button type="button" class="btn" data-clipboard-target="#api-key">Copy</button>
|
||||
@@ -191,11 +178,11 @@ If you created the library yourself, switch to the component and its events:
|
||||
|
||||
The browser API works in secure contexts only, so on plain `http` the copy fails and `error.bs.clipboard` fires. `localhost` counts as secure.
|
||||
|
||||
### Litepicker is replaced by Datepicker
|
||||
### Datepicker replaces Litepicker
|
||||
|
||||
[Litepicker](https://github.com/wakirin/Litepicker) has been archived since 2023, so Tabler dropped it. The package is gone from the dependencies and from `dist/libs`, and its styles are gone from `tabler-vendors.css`. A page that loads `dist/libs/litepicker/dist/litepicker.js` gets a 404 after the upgrade.
|
||||
[Litepicker](https://github.com/wakirin/Litepicker) has been archived since 2023, so Tabler's own pages moved to the new [Datepicker](/ui/plugins/date-picker) plugin. Litepicker is deprecated: `dist/libs/litepicker` and its styles in `tabler-vendors.css` stay until 2.0, so a page that uses it keeps working.
|
||||
|
||||
The new [Datepicker](/ui/plugins/date-picker) plugin is part of `tabler.js`. It renders its calendar with [Vanilla Calendar Pro](https://vanilla-calendar.pro), which you load in place of Litepicker:
|
||||
Datepicker is part of `tabler.js`. It renders its calendar with [Vanilla Calendar Pro](https://vanilla-calendar.pro), which you load in place of Litepicker:
|
||||
|
||||
```diff
|
||||
- <script src="/dist/libs/litepicker/dist/litepicker.js"></script>
|
||||
@@ -218,7 +205,7 @@ Then replace the script that created the picker with a data attribute:
|
||||
+ <input type="text" class="form-control" id="date" data-bs-toggle="datepicker" autocomplete="off" />
|
||||
```
|
||||
|
||||
The Datepicker page has a [table that maps every Litepicker option](/ui/plugins/date-picker#migration-from-litepicker) to its new name. Tabler only removed its own copy and styles, so a project that installs Litepicker on its own keeps working, but without Tabler's look.
|
||||
The Datepicker page has a [table that maps every Litepicker option](/ui/plugins/date-picker#migration-from-litepicker) to its new name.
|
||||
|
||||
### New events
|
||||
|
||||
@@ -231,19 +218,19 @@ Component|Events
|
||||
`CountUp`|`start.bs.countup`, `complete.bs.countup`
|
||||
`SwitchIcon`|`toggle.bs.switch-icon` before the state changes, cancelable with `event.preventDefault()`, then `change.bs.switch-icon`. Both carry the new state in `event.active`.
|
||||
|
||||
## Removed JavaScript helpers
|
||||
## Deprecated JavaScript helpers
|
||||
|
||||
`tabler.js` used to expose a small `tabler` namespace next to the components, with `prefix`, `getColor()` and `hexToRgba()`. It was never documented, but it was easy to find in the source, so some projects picked it up for chart colors:
|
||||
`tabler.js` exposes a small `tabler` namespace next to the components, with `prefix`, `getColor()` and `hexToRgba()`. It was never documented, but it was easy to find in the source, so some projects picked it up for chart colors:
|
||||
|
||||
```js
|
||||
/* 1.5 */
|
||||
/* works in 1.5 and 1.6 */
|
||||
const color = tabler.tabler.getColor('primary', 0.5);
|
||||
```
|
||||
|
||||
The namespace was removed, together with the `prefix` and `hexToRgba` exports. The helper only worked while colors were hex strings, and the palette is `oklch()` now. Read the variable yourself, and use `color-mix()` when you need transparency:
|
||||
The namespace is deprecated and goes away in 2.0. `hexToRgba()` only understands hex strings, and the palette is `oklch()` now, so `getColor()` with an opacity returns a `color-mix()` expression instead of `rgba()`. Read the variable yourself, and use `color-mix()` when you need transparency:
|
||||
|
||||
```js
|
||||
/* 1.6 */
|
||||
/* 1.6 and later */
|
||||
const primary = getComputedStyle(document.body).getPropertyValue('--tblr-primary').trim();
|
||||
const primaryHalf = `color-mix(in oklab, ${primary} 50%, transparent)`;
|
||||
```
|
||||
@@ -259,34 +246,35 @@ In 1.5 `.legend` was a small colored dot. In 1.6 `.legend` is a whole legend ite
|
||||
+ <span class="legend-dot bg-primary"></span>
|
||||
```
|
||||
|
||||
An empty `.legend` still renders as a dot, so nothing breaks today. It is deprecated, so rename it when you touch that markup. See [Legend](/ui/components/legend) for the new item, the list and the interactive states.
|
||||
An empty `.legend` still renders as a dot, so the old markup still works. It is deprecated, so rename it when you touch that markup. See [Legend](/ui/components/legend) for the new item, the list and the interactive states.
|
||||
|
||||
## Form hint is form text
|
||||
|
||||
Tabler had its own `.form-hint` class for the helper text under a field, while Bootstrap calls the same thing `.form-text`. 1.6 uses the Bootstrap class and keeps `.form-hint` as a deprecated alias, so nothing breaks. Rename when you touch the markup anyway:
|
||||
Tabler had its own `.form-hint` class for the helper text under a field, while Bootstrap calls the same thing `.form-text`. 1.6 uses the Bootstrap class and keeps `.form-hint` as a deprecated alias with the same spacing as before, so the old name still works. Rename when you touch the markup anyway:
|
||||
|
||||
```diff
|
||||
- <small class="form-hint">We'll never share your email.</small>
|
||||
+ <div class="form-text">We'll never share your email.</div>
|
||||
```
|
||||
|
||||
The three `$form-hint-*` Sass variables are gone. `.form-text` uses Bootstrap's `$form-text-margin-top`, `$form-text-font-size` and `$form-text-color`.
|
||||
The three `$form-hint-*` Sass variables and `--tblr-form-hint-*` properties only apply to `.form-hint`. `.form-text` uses Bootstrap's `$form-text-margin-top`, `$form-text-font-size` and `$form-text-color`.
|
||||
|
||||
## Masked icons
|
||||
|
||||
The check mark in a checkbox, the dot in a radio, the knob of a switch, the navbar toggler and the carousel arrows used to be SVG background images with the color baked into the SVG. They are CSS masks now, painted with `background-color`. That's what lets them follow the color variables at runtime, and it's why the same checkbox looks right in every theme without a dark variant of the image.
|
||||
|
||||
For most projects this is invisible. It matters if you customized those icons in Sass:
|
||||
For most projects this is invisible. It matters if you customized those icons:
|
||||
|
||||
- `$form-switch-bg-image`, `$form-switch-bg-image-dark`, `$form-switch-checked-bg-image`, `$form-switch-checked-bg-position` and `$form-switch-focus-bg-image` are gone. The switch knob is a plain circle drawn with CSS. Its color comes from `$form-switch-color`, its size from `--tblr-form-switch-knob-size`.
|
||||
- `$form-check-input-checked-bg-image-dark` is gone, because one image now works for both modes. The icon color is `$form-check-input-checked-color`, or `--tblr-form-check-icon-color` at runtime.
|
||||
- `$navbar-light-toggler-icon-bg` and `$navbar-dark-toggler-icon-bg` were merged into `$navbar-toggler-icon-bg`. The color comes from `--tblr-navbar-toggler-icon-color`.
|
||||
- `$form-switch-bg-image`, `$form-switch-bg-image-dark`, `$form-switch-checked-bg-image`, `$form-switch-checked-bg-position` and `$form-switch-focus-bg-image` are deprecated and no longer change the switch. The knob is a plain circle drawn with CSS. Its color comes from `$form-switch-color`, its size from `--tblr-form-switch-knob-size`.
|
||||
- `$form-check-input-checked-bg-image-dark` is deprecated, because one image now works for both modes. The icon color is `$form-check-input-checked-color`, or `--tblr-form-check-icon-color` at runtime.
|
||||
- `$navbar-light-toggler-icon-bg` and `$navbar-dark-toggler-icon-bg` are deprecated in favor of `$navbar-toggler-icon-bg`. The color comes from `--tblr-navbar-toggler-icon-color`.
|
||||
- An image set at runtime through `--tblr-form-check-bg-image` or `--tblr-form-switch-bg` is still painted, under the new icon. Both can show, so move to the color variables when you can.
|
||||
|
||||
If you replaced one of the SVGs with your own, keep the shape but drop the `fill` and `stroke` colors from it. The mask only looks at the alpha channel, so any color inside the SVG is ignored.
|
||||
|
||||
## The focus ring is an outline
|
||||
|
||||
In 1.5 the focus indicator was a `box-shadow`, a solid 2px ring with a soft `0.25rem` halo around it. In 1.6 it's an `outline`, the way Bootstrap 6 draws it. Every component uses the same three variables on `:root`:
|
||||
In 1.5 the focus indicator was a `box-shadow`, a solid 2px ring with a soft `0.25rem` halo around it. In 1.6 it's an `outline`, the way Bootstrap 6 draws it. Every component uses the same three variables:
|
||||
|
||||
```css
|
||||
:root {
|
||||
@@ -298,7 +286,7 @@ In 1.5 the focus indicator was a `box-shadow`, a solid 2px ring with a soft `0.2
|
||||
|
||||
The color is `--tblr-primary` mixed with `--tblr-body-bg`, at `--tblr-focus-ring-opacity` (`0.5`) in light mode and `--tblr-focus-ring-opacity-dark` (`0.75`) in dark mode. It follows `--tblr-primary`, so a recolored theme gets a matching ring for free.
|
||||
|
||||
The per-component shadow variables are gone. If you changed the ring of one component, set the ring variables on it instead:
|
||||
The per-component shadow variables are deprecated. A shadow you set through one of them is still drawn, next to the outline. To restyle the ring itself, set the ring variables on the component:
|
||||
|
||||
```diff
|
||||
.btn {
|
||||
@@ -308,11 +296,11 @@ The per-component shadow variables are gone. If you changed the ring of one comp
|
||||
}
|
||||
```
|
||||
|
||||
The same goes for `--tblr-pagination-focus-box-shadow`, `--tblr-accordion-btn-focus-box-shadow` and `--tblr-btn-close-focus-shadow`.
|
||||
The same goes for `--tblr-pagination-focus-box-shadow`, `--tblr-accordion-btn-focus-box-shadow`, `--tblr-btn-close-focus-shadow`, and for `--tblr-focus-ring-x`, `--tblr-focus-ring-y` and `--tblr-focus-ring-blur` on the `.focus-ring` helper.
|
||||
|
||||
Form controls draw the ring over their border with `--tblr-focus-ring-offset: -1px`. Buttons and everything else draw it `2px` outside.
|
||||
|
||||
If you write your own components, the `focus-ring()` mixin gives them the same ring. Pass `true` to apply the offset, and a color as the second argument to override it:
|
||||
If you write your own components, the `focus-ring()` mixin gives them the same ring. Pass `true` to draw it over the border, and a color as the second argument to override it:
|
||||
|
||||
```scss
|
||||
.my-control:focus-visible {
|
||||
@@ -320,29 +308,31 @@ If you write your own components, the `focus-ring()` mixin gives them the same r
|
||||
}
|
||||
```
|
||||
|
||||
`focus-ring($show-border: true)` from 1.5 still compiles and means the same thing.
|
||||
|
||||
The `.focus-ring` helper is fixed along the way. It now shows on `:focus-visible` instead of `:focus`, so a mouse click no longer draws it.
|
||||
|
||||
## Sass changes
|
||||
|
||||
Only relevant if you compile `scss/tabler.scss` yourself.
|
||||
|
||||
### Removed variables
|
||||
### Deprecated variables
|
||||
|
||||
Variable|What to do instead
|
||||
These still exist, so `@use … with (…)` and your own code that reads them keep compiling. They live in `scss/_variables-deprecated.scss` and are removed in 2.0.
|
||||
|
||||
Variable|What to use instead
|
||||
---|---
|
||||
`$theme-colors-rgb`|Nothing. Tabler doesn't emit RGB triplets, and neither should your code.
|
||||
`$form-hint-margin-top`, `$form-hint-label-offset`, `$form-hint-control-margin-top`|Use `$form-text-margin-top` and friends.
|
||||
`$form-switch-bg-image`, `$form-switch-bg-image-dark`, `$form-switch-checked-bg-image`, `$form-switch-checked-bg-position`, `$form-switch-focus-bg-image`|See [Masked icons](#masked-icons).
|
||||
`$form-check-input-checked-bg-image-dark`|See [Masked icons](#masked-icons).
|
||||
`$navbar-light-toggler-icon-bg`, `$navbar-dark-toggler-icon-bg`|Use `$navbar-toggler-icon-bg`.
|
||||
`$focus-ring-blur`, `$focus-ring-box-shadow`|Use `$focus-ring-width`, `$focus-ring-offset` and `$focus-ring-color`. See [The focus ring is an outline](#the-focus-ring-is-an-outline).
|
||||
`$input-btn-focus-width`, `$input-btn-focus-color-opacity`, `$input-btn-focus-color`, `$input-btn-focus-blur`, `$input-btn-focus-box-shadow`|Same as above.
|
||||
`$input-focus-width`, `$input-focus-box-shadow`, `$btn-focus-box-shadow`, `$form-select-focus-width`, `$form-select-focus-box-shadow`, `$form-check-input-focus-box-shadow`, `$form-range-thumb-focus-box-shadow`|Same as above.
|
||||
`$nav-link-focus-box-shadow`, `$pagination-focus-box-shadow`, `$pagination-focus-outline`, `$accordion-btn-focus-box-shadow`, `$btn-close-focus-shadow`|Same as above.
|
||||
`$theme-colors-rgb`|Nothing. Use `color-mix()` on the color itself.
|
||||
`$form-hint-margin-top`, `$form-hint-label-offset`, `$form-hint-control-margin-top`|`$form-text-margin-top` and friends. The old ones still style `.form-hint`.
|
||||
`$form-switch-bg-image`, `$form-switch-bg-image-dark`, `$form-switch-checked-bg-image`, `$form-switch-checked-bg-position`, `$form-switch-focus-bg-image`, `$form-switch-color-dark`|See [Masked icons](#masked-icons). No effect any more.
|
||||
`$form-check-input-checked-bg-image-dark`|See [Masked icons](#masked-icons). No effect any more.
|
||||
`$navbar-light-toggler-icon-bg`, `$navbar-dark-toggler-icon-bg`|`$navbar-toggler-icon-bg`. No effect any more.
|
||||
`$input-btn-focus-width`|`$focus-ring-width`. A changed value still sets the ring width.
|
||||
`$input-btn-focus-color`|`$focus-ring-color`. A changed value still sets the ring color.
|
||||
`$btn-focus-box-shadow`, `$btn-close-focus-shadow`, `$pagination-focus-box-shadow`, `$accordion-btn-focus-box-shadow`|The ring variables. A changed value is still drawn as a shadow, next to the outline.
|
||||
`$focus-ring-blur`, `$focus-ring-box-shadow`, `$input-btn-focus-color-opacity`, `$input-btn-focus-blur`, `$input-btn-focus-box-shadow`, `$input-focus-width`, `$input-focus-box-shadow`, `$form-select-focus-width`, `$form-select-focus-box-shadow`, `$form-check-input-focus-box-shadow`, `$form-range-thumb-focus-box-shadow`, `$nav-link-focus-box-shadow`, `$pagination-focus-outline`|`$focus-ring-width`, `$focus-ring-offset` and `$focus-ring-color`. See [The focus ring is an outline](#the-focus-ring-is-an-outline). No effect any more.
|
||||
|
||||
Setting a removed variable in `@use … with (…)` is a compile error in Sass, so you'll notice right away.
|
||||
|
||||
In `$form-validation-states` the `focus-box-shadow` key is now `focus-ring-color`, and it takes a color instead of a shadow:
|
||||
In `$form-validation-states` the new key is `focus-ring-color`, and it takes a color. A `focus-box-shadow` key from 1.5 is still drawn:
|
||||
|
||||
```diff
|
||||
'invalid': (
|
||||
@@ -352,11 +342,22 @@ In `$form-validation-states` the `focus-box-shadow` key is now `focus-ring-color
|
||||
),
|
||||
```
|
||||
|
||||
Two defaults changed too: `$focus-ring-width` went from `0.25rem` to `2px`, and `$focus-ring-opacity` from `0.25` to `0.5`.
|
||||
Two defaults changed with the outline: `$focus-ring-width` went from `0.25rem` to `2px`, and `$focus-ring-opacity` from `0.25` to `0.5`.
|
||||
|
||||
### Removed functions
|
||||
### Deprecated functions
|
||||
|
||||
`theme-color-lighter()` and `theme-color-darker()` computed a tint and a shade at compile time. They were removed with the RGB variables. Two pairs of functions replace them:
|
||||
These still work and warn when you compile. They live in `scss/mixins/_deprecated.scss` and are removed in 2.0.
|
||||
|
||||
Function or mixin|What to use instead
|
||||
---|---
|
||||
`theme-color-lighter($color)`|`mix-color($color, #fff, 10%)`, or `mix-color-css()` for a value that follows `--tblr-*` overrides
|
||||
`theme-color-darker($color)`|`shade-color($color, 10%)`, or `adjust-lightness-css(var(--primary), -6%)`
|
||||
`url-svg($svg)`|`escape-svg(url("data:image/svg+xml,…"))`
|
||||
`varify($list)`|Write the `var()` values by hand
|
||||
`map-get-multiple()`, `map-merge-multiple()`|`map.get()` and `map.merge()` from `sass:map`
|
||||
`breakpoint-prev()`, `media-breakpoint-down-than()`|`media-breakpoint-down()` with the breakpoint one step down
|
||||
|
||||
Two pairs of functions are new:
|
||||
|
||||
- `mix-color($a, $b, $weight)` and `adjust-lightness($color, $amount)` work at compile time on Sass colors and return an sRGB color, so the result can still feed `color-contrast()` or `luminance()`.
|
||||
- `mix-color-css($a, $b, $weight)` and `adjust-lightness-css($color, $amount)` return a `color-mix()` or a relative `oklch()` expression, so the result follows `--tblr-*` overrides in the browser. Use these where the value is emitted as it is.
|
||||
@@ -366,34 +367,34 @@ Two defaults changed too: `$focus-ring-width` went from `0.25rem` to `2px`, and
|
||||
+ $my-hover: adjust-lightness-css(var(--primary), -10%);
|
||||
```
|
||||
|
||||
`url-svg()`, `varify()`, `map-get-multiple()`, `map-merge-multiple()`, `breakpoint-prev()` and the `media-breakpoint-down-than` mixin were unused inside Tabler and were removed too. If you called one of them, copy it into your own project from the 1.5 sources.
|
||||
|
||||
### Variables that turned into color-mix()
|
||||
|
||||
A lot of Bootstrap variables that were plain Sass colors are now `color-mix()` expressions on top of a custom property. `$primary-bg-subtle`, for example, used to be `tint-color($primary, 80%)`, and is now `mix-color-css(var(--white), var(--primary), 80%)`. The same happened to the `*-text-emphasis`, `*-border-subtle`, `$focus-ring-color`, `$input-focus-border-color` and most `rgba($black, …)` shadows.
|
||||
This is the one change in 1.6 that can stop a Sass build, and the one exception to "nothing breaks". 69 variables that were plain Sass colors are now `color-mix()` expressions on top of a custom property, so that they follow `--tblr-*` overrides in the browser. `$primary-bg-subtle`, for example, used to be `tint-color($primary, 80%)`, and is now `mix-color-css(var(--white), var(--primary), 80%)`. The same happened to the `*-bg-subtle`, `*-text-emphasis` and `*-border-subtle` families and their `-dark` twins, `$body-secondary-color`, `$body-tertiary-color`, `$input-focus-border-color`, the dark mode border colors, and a few navbar, dropdown and switch colors. The theme colors such as `$primary`, the grays, `$body-color`, `$body-bg` and `$link-color` are still Sass colors.
|
||||
|
||||
You can still override them with anything Sass accepts. Just be aware that a Sass color function such as `darken()` or `rgba()` won't work on their default values any more, because the default isn't a color, it's a string with `var()` inside.
|
||||
|
||||
## The default gray is neutral
|
||||
|
||||
Every gray in Tabler comes from the `--tblr-gray-50` … `--tblr-gray-950` scale. In 1.5 that scale had a blue tint. In 1.6 the default is `neutral`, a pure gray, so backgrounds, borders and muted text look slightly different. The Sass defaults `$gray-50` … `$gray-950` changed the same way.
|
||||
|
||||
The old scale ships in `tabler-themes.css` as `gray`. To keep the 1.5 look, load that stylesheet and set the base on `<html>`:
|
||||
You can still override them with anything Sass accepts. But a Sass color function such as `darken()` or `rgba()` fails on their default values, because the default isn't a color, it's a string with `var()` inside. Build the value from the base color instead, with Tabler's own functions:
|
||||
|
||||
```diff
|
||||
- <html>
|
||||
+ <html data-bs-theme-base="gray">
|
||||
<head>
|
||||
<link rel="stylesheet" href="/dist/css/tabler.min.css" />
|
||||
+ <link rel="stylesheet" href="/dist/css/tabler-themes.min.css" />
|
||||
- $my-subtle-hover: darken($primary-bg-subtle, 5%);
|
||||
+ $my-subtle-hover: shade-color(tint-color($primary, 80%), 5%);
|
||||
```
|
||||
|
||||
`tabler-theme.js` also treats `neutral` as the default now. A visitor who picked `gray` in the theme settings keeps it. See [Theme base colors](/ui/plugins/theme-base-colors) for the other palettes.
|
||||
### Dropping the deprecated layer
|
||||
|
||||
Everything on this page that is kept for older projects sits behind one flag. Once your project no longer uses any of it, turn the flag off and the CSS gets about 1.4 kB (gzip) smaller:
|
||||
|
||||
```scss
|
||||
@use '@tabler/core/scss/tabler' with (
|
||||
$enable-deprecated: false
|
||||
);
|
||||
```
|
||||
|
||||
That is also a good test before 2.0: if the project still looks right with the flag off, the CSS side of the upgrade is done.
|
||||
|
||||
## Visual changes
|
||||
|
||||
None of these break markup, but they change how a page looks or scrolls. Worth a quick look at your screens after the upgrade.
|
||||
|
||||
- **The default gray is neutral.** Every gray in Tabler comes from the `--tblr-gray-50` … `--tblr-gray-950` scale. In 1.5 that scale had a slight blue tint; in 1.6 the default is `neutral`, a pure gray, so backgrounds, borders and muted text look a little different. The Sass defaults `$gray-50` … `$gray-950` changed the same way. To keep the 1.5 look, load `tabler-themes.css` and set `data-bs-theme-base="gray"` on `<html>`. A visitor who picked `gray` in the theme settings keeps it. See [Theme base colors](/ui/plugins/theme-base-colors).
|
||||
- **The focus ring is a solid outline.** The soft halo around focused buttons and inputs is gone. Focus is a single 2px ring, stronger in dark mode. See [The focus ring is an outline](#the-focus-ring-is-an-outline).
|
||||
- **No reserved scrollbar gutter.** 1.5 set `scrollbar-gutter: stable` on `html`, which left an empty strip on the right of the navbar on pages too short to scroll. That rule is gone. Layout shifts between short and long pages are back to the browser default, which on macOS and most mobile browsers means none.
|
||||
- **Scroll chaining is contained.** Scrolling to the end of a modal body, an offcanvas body or a scrollable dropdown no longer scrolls the page behind it.
|
||||
@@ -419,7 +420,7 @@ Besides the changes above, 1.6 adds:
|
||||
- `Autosize`, `CountUp`, `InputMask`, `Sortable` and `SwitchIcon` as real components with instances, methods and events, see above.
|
||||
- `data-tblr-countup` as an alias of `data-countup`.
|
||||
- `.navbar-floating` for [navbars](/ui/layout/navbars) and `.offcanvas-floating` for [offcanvas](/ui/components/offcanvas), which detach the element from the edge of the screen.
|
||||
- Drag styles for [Sortable](/ui/plugins/sortable): `.sortable-ghost`, `.sortable-chosen` and `.sortable-drag`.
|
||||
- Drag styles for [Sortable](/ui/plugins/sortable): `.sortable-ghost`, `.sortable-chosen`, and `.sortable-drag` for lists that turn on `forceFallback`.
|
||||
- A billing page in the preview, with plan usage, payment method and invoices.
|
||||
- The Bootstrap component port is compiled with strict TypeScript, so the type declarations in the package are tighter. Configs are typed per component.
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ document.getElementById('my-date').addEventListener('change.bs.datepicker', (eve
|
||||
|
||||
## Migration from Litepicker
|
||||
|
||||
Tabler 1.5 and older used [Litepicker](https://github.com/wakirin/Litepicker), which has been archived since 2023. It is no longer shipped in `dist/libs`, and its styles are gone from `tabler-vendors.css`. Load Vanilla Calendar Pro instead and switch the markup as shown below.
|
||||
Tabler 1.5 and older used [Litepicker](https://github.com/wakirin/Litepicker), which has been archived since 2023. It is deprecated: `dist/libs/litepicker` and its styles in `tabler-vendors.css` stay until 2.0, so existing pages keep working. To move over, load Vanilla Calendar Pro instead and switch the markup as shown below.
|
||||
|
||||
| Litepicker | Datepicker |
|
||||
| --- | --- |
|
||||
|
||||
@@ -97,10 +97,10 @@ Put `data-sortable` on the `tbody` to reorder the rows of a table.
|
||||
|
||||
Tabler styles the classes SortableJS adds while dragging: `.sortable-ghost` marks the drop position, `.sortable-chosen` the picked item and `.sortable-drag` the copy that follows the pointer.
|
||||
|
||||
The component turns on the `forceFallback` option by default. SortableJS then drags an HTML copy of the item instead of the browser's drag image, so `.sortable-drag` can style it. To get the browser's drag image back, turn the option off:
|
||||
The browser draws the dragged item itself by default, and CSS cannot style that image. Turn on the `forceFallback` option and SortableJS drags an HTML copy of the item instead, which `.sortable-drag` tilts and lifts with a shadow:
|
||||
|
||||
```html
|
||||
<ul class="list-group" data-sortable='{"forceFallback":false}'>
|
||||
<ul class="list-group" data-sortable='{"forceFallback":true}'>
|
||||
…
|
||||
</ul>
|
||||
```
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"check:docs-links": "tsx .build/check-docs-links.ts",
|
||||
"check:css-vars": "tsx .build/check-css-vars.ts",
|
||||
"check:compat": "tsx .build/check-compat.ts",
|
||||
"check:compat-fixture": "tsx .build/check-compat-fixture.ts",
|
||||
"check:open-source": "tsx .build/check-open-source.ts",
|
||||
"check:html": "tsx .build/check-html.ts",
|
||||
"check:markup-classes": "tsx .build/check-markup-classes.ts",
|
||||
|
||||
Generated
+58
@@ -132,9 +132,18 @@ importers:
|
||||
apexcharts:
|
||||
specifier: 7.0.0
|
||||
version: 7.0.0
|
||||
autosize:
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
choices.js:
|
||||
specifier: ^11.2.4
|
||||
version: 11.2.4
|
||||
clipboard:
|
||||
specifier: ^2.0.11
|
||||
version: 2.0.11
|
||||
countup.js:
|
||||
specifier: ^2.10.1
|
||||
version: 2.10.1
|
||||
driver.js:
|
||||
specifier: ^1.8.0
|
||||
version: 1.8.0
|
||||
@@ -165,6 +174,9 @@ importers:
|
||||
list.js:
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1
|
||||
litepicker:
|
||||
specifier: ^2.0.12
|
||||
version: 2.0.12
|
||||
nouislider:
|
||||
specifier: ^15.8.1
|
||||
version: 15.8.1
|
||||
@@ -2086,6 +2098,9 @@ packages:
|
||||
peerDependencies:
|
||||
postcss: ^8.1.0
|
||||
|
||||
autosize@6.0.1:
|
||||
resolution: {integrity: sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==}
|
||||
|
||||
axios@0.33.0:
|
||||
resolution: {integrity: sha512-juz19g7B3UWT9r3+tgRFQf2Bdy6IKDVroiyuVOUrkILVKHpqHL++K1l8ybvfdEP9B/VE72vk8vllbnedVCm/og==}
|
||||
|
||||
@@ -2224,6 +2239,9 @@ packages:
|
||||
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
|
||||
engines: {node: '>= 10.0'}
|
||||
|
||||
clipboard@2.0.11:
|
||||
resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==}
|
||||
|
||||
cliui@9.0.1:
|
||||
resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==}
|
||||
engines: {node: '>=20'}
|
||||
@@ -2323,6 +2341,9 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
countup.js@2.10.1:
|
||||
resolution: {integrity: sha512-UHW/BsPDgVZfN919D4iu2HPv+jJxZUuaR3EhT0ScFZaD446GiQtkMTgOnOyJXdA2AewdlyUk9UvERlTHTbVpcw==}
|
||||
|
||||
cross-env@10.1.0:
|
||||
resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==}
|
||||
engines: {node: '>=20'}
|
||||
@@ -2393,6 +2414,9 @@ packages:
|
||||
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
delegate@3.2.0:
|
||||
resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
|
||||
|
||||
dequal@2.0.3:
|
||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -2751,6 +2775,9 @@ packages:
|
||||
globjoin@0.1.4:
|
||||
resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==}
|
||||
|
||||
good-listener@1.2.2:
|
||||
resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==}
|
||||
|
||||
gopd@1.2.0:
|
||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -3239,6 +3266,9 @@ packages:
|
||||
resolution: {integrity: sha512-jnmm7DYpKtH3DxtO1E2VNCC9Gp7Wrp/FWA2JxQrZUhVJ2RCQBd57pCN6W5w6jpsfWZV0PCAbTX2NOPgyFeeZZg==}
|
||||
engines: {node: ^6.0 || ^8.0 || ^10.0 || ^12.0 || >=14}
|
||||
|
||||
litepicker@2.0.12:
|
||||
resolution: {integrity: sha512-1N0sZJca/eALvS1hbJsVqKXwJAmp0BsJn73kZKWGGLjZkvjKr7HXGPV+/shu60aEY/JXoOg2XUmo7hbdIOsFpQ==}
|
||||
|
||||
loadjs@4.3.0:
|
||||
resolution: {integrity: sha512-vNX4ZZLJBeDEOBvdr2v/F+0aN5oMuPu7JTqrMwp+DtgK+AryOlpy6Xtm2/HpNr+azEa828oQjOtWsB6iDtSfSQ==}
|
||||
|
||||
@@ -4043,6 +4073,9 @@ packages:
|
||||
resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==}
|
||||
engines: {node: '>=11.0.0'}
|
||||
|
||||
select@1.1.2:
|
||||
resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==}
|
||||
|
||||
semver@5.7.2:
|
||||
resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
|
||||
hasBin: true
|
||||
@@ -4331,6 +4364,9 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
tiny-emitter@2.1.0:
|
||||
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
|
||||
|
||||
tiny-inflate@1.0.3:
|
||||
resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
|
||||
|
||||
@@ -6621,6 +6657,8 @@ snapshots:
|
||||
postcss: 8.5.28
|
||||
postcss-value-parser: 4.2.0
|
||||
|
||||
autosize@6.0.1: {}
|
||||
|
||||
axios@0.33.0(debug@4.4.3(supports-color@10.2.2)):
|
||||
dependencies:
|
||||
follow-redirects: 1.16.0(debug@4.4.3(supports-color@10.2.2))
|
||||
@@ -6761,6 +6799,12 @@ snapshots:
|
||||
dependencies:
|
||||
source-map: 0.6.1
|
||||
|
||||
clipboard@2.0.11:
|
||||
dependencies:
|
||||
good-listener: 1.2.2
|
||||
select: 1.1.2
|
||||
tiny-emitter: 2.1.0
|
||||
|
||||
cliui@9.0.1:
|
||||
dependencies:
|
||||
string-width: 7.2.0
|
||||
@@ -6838,6 +6882,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 7.0.2
|
||||
|
||||
countup.js@2.10.1: {}
|
||||
|
||||
cross-env@10.1.0:
|
||||
dependencies:
|
||||
'@epic-web/invariant': 1.0.0
|
||||
@@ -6913,6 +6959,8 @@ snapshots:
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
delegate@3.2.0: {}
|
||||
|
||||
dequal@2.0.3: {}
|
||||
|
||||
destr@2.0.5: {}
|
||||
@@ -7321,6 +7369,10 @@ snapshots:
|
||||
|
||||
globjoin@0.1.4: {}
|
||||
|
||||
good-listener@1.2.2:
|
||||
dependencies:
|
||||
delegate: 3.2.0
|
||||
|
||||
gopd@1.2.0: {}
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
@@ -7791,6 +7843,8 @@ snapshots:
|
||||
dependencies:
|
||||
string-natural-compare: 2.0.3
|
||||
|
||||
litepicker@2.0.12: {}
|
||||
|
||||
loadjs@4.3.0: {}
|
||||
|
||||
locate-path@5.0.0:
|
||||
@@ -8964,6 +9018,8 @@ snapshots:
|
||||
|
||||
sax@1.6.1: {}
|
||||
|
||||
select@1.1.2: {}
|
||||
|
||||
semver@5.7.2: {}
|
||||
|
||||
semver@6.3.1: {}
|
||||
@@ -9328,6 +9384,8 @@ snapshots:
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
|
||||
tiny-emitter@2.1.0: {}
|
||||
|
||||
tiny-inflate@1.0.3: {}
|
||||
|
||||
tinybench@2.9.0: {}
|
||||
|
||||
@@ -282,7 +282,7 @@ const sections = [
|
||||
<CardHeader>
|
||||
<div>
|
||||
<CardTitle as="h3">Kanban board</CardTitle>
|
||||
<CardSubtitle>Drag tasks between columns that share one <code>group</code>. Items are dragged as a tilted copy with a shadow. Set <code>forceFallback</code> to <code>false</code> to use the browser preview instead.</CardSubtitle>
|
||||
<CardSubtitle>Drag tasks between columns that share one <code>group</code>. Set <code>forceFallback</code> to <code>true</code> to drag a tilted copy with a shadow instead of the browser preview.</CardSubtitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
@@ -291,7 +291,7 @@ const sections = [
|
||||
board.map((column) => (
|
||||
<div class="col-md-4">
|
||||
<h4 class="mb-2">{column.name}</h4>
|
||||
<div class="d-flex flex-column gap-2" data-sortable='{"group":"kanban","animation":150,"emptyInsertThreshold":40}'>
|
||||
<div class="d-flex flex-column gap-2" data-sortable='{"group":"kanban","animation":150,"emptyInsertThreshold":40,"forceFallback":true}'>
|
||||
{column.tasks.map((task) => (
|
||||
<div class="card card-sm cursor-move">
|
||||
<div class="card-body">
|
||||
@@ -381,17 +381,17 @@ const sections = [
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<ListGroup as="ul" data-sortable='{"group":"nested","animation":150,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroup as="ul" data-sortable='{"group":"nested","animation":150,"forceFallback":true,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroupItem as="li">
|
||||
<div>Design</div>
|
||||
<ListGroup as="ul" class="mt-2" data-sortable='{"group":"nested","animation":150,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroup as="ul" class="mt-2" data-sortable='{"group":"nested","animation":150,"forceFallback":true,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroupItem as="li">Wireframes</ListGroupItem>
|
||||
<ListGroupItem as="li">Prototype</ListGroupItem>
|
||||
</ListGroup>
|
||||
</ListGroupItem>
|
||||
<ListGroupItem as="li">
|
||||
<div>Development</div>
|
||||
<ListGroup as="ul" class="mt-2" data-sortable='{"group":"nested","animation":150,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroup as="ul" class="mt-2" data-sortable='{"group":"nested","animation":150,"forceFallback":true,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroupItem as="li">Frontend</ListGroupItem>
|
||||
<ListGroupItem as="li">Backend</ListGroupItem>
|
||||
<ListGroupItem as="li">Tests</ListGroupItem>
|
||||
@@ -399,7 +399,7 @@ const sections = [
|
||||
</ListGroupItem>
|
||||
<ListGroupItem as="li">
|
||||
<div>Launch</div>
|
||||
<ListGroup as="ul" class="mt-2" data-sortable='{"group":"nested","animation":150,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroup as="ul" class="mt-2" data-sortable='{"group":"nested","animation":150,"forceFallback":true,"fallbackOnBody":true,"swapThreshold":0.65}'>
|
||||
<ListGroupItem as="li">Release notes</ListGroupItem>
|
||||
</ListGroup>
|
||||
</ListGroupItem>
|
||||
|
||||
@@ -6,12 +6,26 @@
|
||||
"description": "Modern charting library offering interactive and responsive charts.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "Autosize",
|
||||
"npm": "autosize",
|
||||
"url": "https://www.jacklmoore.com/autosize/",
|
||||
"description": "Automatically adjusts textarea height to fit text content. Kept in dist/libs for older projects; Tabler has its own Autosize component.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "Bootstrap",
|
||||
"url": "https://getbootstrap.com/",
|
||||
"description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "clipboard.js",
|
||||
"npm": "clipboard",
|
||||
"url": "https://clipboardjs.com/",
|
||||
"description": "Copies text to the clipboard. Kept in dist/libs for older projects; Tabler has its own Clipboard component.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "Coloris",
|
||||
"npm": "@melloware/coloris",
|
||||
@@ -19,6 +33,13 @@
|
||||
"description": "Lightweight and elegant color picker written in vanilla JavaScript.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "CountUp.js",
|
||||
"npm": "countup.js",
|
||||
"url": "https://inorganik.github.io/countUp.js/",
|
||||
"description": "Animates numerical values by counting up to them. Kept in dist/libs for older projects; Tabler has its own CountUp component.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "Driver.js",
|
||||
"npm": "driver.js",
|
||||
@@ -75,6 +96,13 @@
|
||||
"description": "Adds search, sort, and flexibility to tables, lists, and various HTML elements.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "Litepicker",
|
||||
"npm": "litepicker",
|
||||
"url": "https://github.com/wakirin/Litepicker",
|
||||
"description": "Lightweight, no-dependency date range picker. Kept in dist/libs for older projects; use the Datepicker plugin instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "Mapbox GL JS",
|
||||
"lib": "mapbox",
|
||||
|
||||
Reference in new issue
Block a user