1
0
mirror of https://github.com/tabler/tabler.git synced 2026-08-05 19:03:18 +04:00

Merge branch 'dev' into list-group-docs

This commit is contained in:
Bartosz-Do
2026-08-05 13:31:39 +02:00
committed by GitHub
49 changed files with 526 additions and 205 deletions
@@ -0,0 +1,7 @@
---
"@tabler/core": patch
---
Migrated all physical CSS direction properties to logical properties (`padding-inline`, `margin-inline`, `inset-inline`, `float: inline-start`/`inline-end`, `text-align: start/end`) for improved RTL support and reduced RTL stylesheet generation overhead.
Directional transforms, which have no logical equivalent, now use a `--tblr-dir` direction multiplier (`1` in LTR, `-1` under `[dir="rtl"]`), e.g. `translateX(calc(var(--tblr-dir) * 4px))`. These declarations are identical in `tabler.css` and `tabler.rtl.css` — the flip happens at runtime via the `dir` attribute, so RTL transforms now also work when using plain `tabler.css` with `dir="rtl"`.
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/core": patch
---
Fixed oversized `dist/libs` by copying only the runtime files each library declares in `libs.json`, plus the assets HugeRTE loads at runtime and every upstream license file.
+35 -5
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env node
import { existsSync, mkdirSync } from 'node:fs'
import { globSync } from 'glob'
import { emptyDirSync, copySync } from 'fs-extra/esm'
import libs from '../libs.json' with { type: 'json' }
import { fileURLToPath } from 'node:url'
@@ -12,6 +13,7 @@ interface LibConfig {
npm?: string
js?: string[]
css?: string[]
extra?: string[]
head?: boolean
}
@@ -24,10 +26,10 @@ const libsData = libs as Libs
emptyDirSync(join(__dirname, '..', 'dist/libs'))
for (const name in libsData) {
const { npm } = libsData[name]
const { npm, js, css, extra } = libsData[name]
if (npm) {
const from = join(__dirname, '..', `node_modules/${npm}`)
const pkgDir = join(__dirname, '..', `node_modules/${npm}`)
const to = join(__dirname, '..', `dist/libs/${npm}`)
// create dir in dist/libs
@@ -35,9 +37,37 @@ for (const name in libsData) {
mkdirSync(to, { recursive: true })
}
copySync(from, to, {
dereference: true,
})
const files = [...(js || []), ...(css || [])]
for (const pattern of extra || []) {
const matches = globSync(pattern, { cwd: pkgDir, nodir: true, posix: true })
if (matches.length === 0) {
throw new Error(`copy-libs: ${name} — "${pattern}" matched no files in ${npm}`)
}
files.push(...matches)
}
if (files) {
for (const file of files) {
copySync(join(pkgDir, file), join(to, file), {
dereference: true,
})
}
}
// Ship each upstream license alongside its files — we redistribute the
// built bundles, and MIT/BSD/Apache all require the notice to travel with them.
const licenses = globSync('{license,licence,copying}*', { cwd: pkgDir, nodir: true, nocase: true })
if (licenses.length === 0) {
console.warn(`Warning: no license file found for ${npm}`)
}
for (const file of licenses) {
copySync(join(pkgDir, file), join(to, file), {
dereference: true,
})
}
console.log(`Successfully copied ${npm}`)
}
+12
View File
@@ -98,6 +98,18 @@
"npm": "hugerte",
"js": [
"hugerte.min.js"
],
"extra": [
"themes/silver/theme.min.js",
"models/dom/model.min.js",
"icons/default/icons.min.js",
"plugins/*/plugin.min.js",
"plugins/help/js/i18n/keynav/*.js",
"plugins/emoticons/js/*.min.js",
"skins/ui/oxide/*.min.css",
"skins/ui/oxide-dark/*.min.css",
"skins/content/default/content.min.css",
"skins/content/dark/content.min.css"
]
},
"plyr": {
+11
View File
@@ -3,6 +3,9 @@
:root,
:host {
/** Direction multiplier for physical transforms (1 = LTR, -1 = RTL) */
--#{$prefix}dir: 1;
/** Fonts */
--#{$prefix}font-monospace: #{$font-family-monospace};
--#{$prefix}font-sans-serif: #{$font-family-sans-serif};
@@ -90,3 +93,11 @@
--#{$prefix}backdrop-blur: #{$backdrop-blur};
--#{$prefix}backdrop-filter: blur(var(--#{$prefix}backdrop-blur));
}
[dir='ltr'] {
--#{$prefix}dir: 1;
}
[dir='rtl'] {
--#{$prefix}dir: -1;
}
+15 -15
View File
@@ -36,8 +36,8 @@ $utilities: map.merge(
responsive: true,
property: float,
values: (
start: left,
end: right,
start: inline-start,
end: inline-end,
none: none,
),
),
@@ -112,12 +112,12 @@ $utilities: map.merge(
values: $position-values,
),
'start': (
property: left,
property: inset-inline-start,
class: start,
values: $position-values,
),
'end': (
property: right,
property: inset-inline-end,
class: end,
values: $position-values,
),
@@ -125,8 +125,8 @@ $utilities: map.merge(
property: transform,
class: translate-middle,
values: (
null: translate(-50%, -50%),
x: translateX(-50%),
null: translate(calc(var(--#{$prefix}dir) * -50%), -50%) #{'/*rtl:ignore*/'},
x: translateX(calc(var(--#{$prefix}dir) * -50%)) #{'/*rtl:ignore*/'},
y: translateY(-50%),
),
),
@@ -395,7 +395,7 @@ $utilities: map.merge(
),
'margin-x': (
responsive: true,
property: margin-right margin-left,
property: margin-inline-end margin-inline-start,
class: mx,
values: map.merge(
$spacers,
@@ -428,7 +428,7 @@ $utilities: map.merge(
),
'margin-end': (
responsive: true,
property: margin-right,
property: margin-inline-end,
class: me,
values: map.merge(
$spacers,
@@ -450,7 +450,7 @@ $utilities: map.merge(
),
'margin-start': (
responsive: true,
property: margin-left,
property: margin-inline-start,
class: ms,
values: map.merge(
$spacers,
@@ -468,7 +468,7 @@ $utilities: map.merge(
),
'negative-margin-x': (
responsive: true,
property: margin-right margin-left,
property: margin-inline-end margin-inline-start,
class: mx,
values: $negative-spacers,
),
@@ -486,7 +486,7 @@ $utilities: map.merge(
),
'negative-margin-end': (
responsive: true,
property: margin-right,
property: margin-inline-end,
class: me,
values: $negative-spacers,
),
@@ -498,7 +498,7 @@ $utilities: map.merge(
),
'negative-margin-start': (
responsive: true,
property: margin-left,
property: margin-inline-start,
class: ms,
values: $negative-spacers,
),
@@ -511,7 +511,7 @@ $utilities: map.merge(
),
'padding-x': (
responsive: true,
property: padding-right padding-left,
property: padding-inline-end padding-inline-start,
class: px,
values: $spacers,
),
@@ -529,7 +529,7 @@ $utilities: map.merge(
),
'padding-end': (
responsive: true,
property: padding-right,
property: padding-inline-end,
class: pe,
values: $spacers,
),
@@ -541,7 +541,7 @@ $utilities: map.merge(
),
'padding-start': (
responsive: true,
property: padding-left,
property: padding-inline-start,
class: ps,
values: $spacers,
),
+1 -1
View File
@@ -1957,7 +1957,7 @@ $form-floating-input-padding-t: 1.625rem !default;
$form-floating-input-padding-b: 0.625rem !default;
$form-floating-label-height: 1.5em !default;
$form-floating-label-opacity: 0.65 !default;
$form-floating-label-transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem) !default;
$form-floating-label-transform: scale(0.85) translateY(-0.5rem) translateX(calc(var(--#{$prefix}dir) * 0.15rem)) #{'/*rtl:ignore*/'} !default;
$form-floating-label-disabled-color: $gray-600 !default;
$form-floating-transition:
opacity 0.1s ease-in-out,
+9 -9
View File
@@ -43,7 +43,7 @@
// Prevent double borders when buttons are next to each other
> :not(.btn-check:first-child) + .btn,
> .btn-group:not(:first-child) {
margin-left: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list
margin-inline-start: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list
}
// Reset rounded corners
@@ -80,28 +80,28 @@
//
.dropdown-toggle-split {
padding-right: $btn-padding-x * 0.75;
padding-left: $btn-padding-x * 0.75;
padding-inline-end: $btn-padding-x * 0.75;
padding-inline-start: $btn-padding-x * 0.75;
&::after,
.dropup &::after,
.dropend &::after {
margin-left: 0;
margin-inline-start: 0;
}
.dropstart &::before {
margin-right: 0;
margin-inline-end: 0;
}
}
.btn-sm + .dropdown-toggle-split {
padding-right: $btn-padding-x-sm * 0.75;
padding-left: $btn-padding-x-sm * 0.75;
padding-inline-end: $btn-padding-x-sm * 0.75;
padding-inline-start: $btn-padding-x-sm * 0.75;
}
.btn-lg + .dropdown-toggle-split {
padding-right: $btn-padding-x-lg * 0.75;
padding-left: $btn-padding-x-lg * 0.75;
padding-inline-end: $btn-padding-x-lg * 0.75;
padding-inline-start: $btn-padding-x-lg * 0.75;
}
// The clickable button for toggling the menu
+10 -13
View File
@@ -41,8 +41,8 @@
@include box-shadow(var(--#{$prefix}card-box-shadow));
> hr {
margin-right: 0;
margin-left: 0;
margin-inline-end: 0;
margin-inline-start: 0;
}
> .list-group {
@@ -97,7 +97,7 @@
}
+ .card-link {
margin-left: var(--#{$prefix}card-spacer-x);
margin-inline-start: var(--#{$prefix}card-spacer-x);
}
}
@@ -133,9 +133,9 @@
//
.card-header-tabs {
margin-right: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-inline-end: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-inline-start: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
border-bottom: 0;
.nav-link.active {
@@ -145,17 +145,14 @@
}
.card-header-pills {
margin-right: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-inline-end: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
margin-inline-start: calc(-0.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list
}
// Card image
.card-img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
inset: 0;
padding: var(--#{$prefix}card-img-overlay-padding);
@include border-radius(var(--#{$prefix}card-inner-border-radius));
}
@@ -197,8 +194,8 @@
margin-bottom: 0;
+ .card {
margin-left: 0;
border-left: 0;
margin-inline-start: 0;
border-inline-start: 0;
}
// Handle rounded corners
+14 -14
View File
@@ -31,9 +31,9 @@
.carousel-item {
position: relative;
display: none;
float: left;
float: inline-start;
width: 100%;
margin-right: -100%;
margin-inline-end: -100%;
backface-visibility: hidden;
@include transition($carousel-transition);
}
@@ -46,12 +46,14 @@
.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
transform: translateX(100%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * 100%));
}
.carousel-item-prev:not(.carousel-item-end),
.active.carousel-item-start {
transform: translateX(-100%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -100%));
}
//
@@ -114,11 +116,11 @@
}
}
.carousel-control-prev {
left: 0;
inset-inline-start: 0;
background-image: if(sass($enable-gradients): linear-gradient(90deg, rgba($black, 0.25), rgba($black, 0.001)); else: null);
}
.carousel-control-next {
right: 0;
inset-inline-end: 0;
background-image: if(sass($enable-gradients): linear-gradient(270deg, rgba($black, 0.25), rgba($black, 0.001)); else: null);
}
@@ -147,17 +149,16 @@
.carousel-indicators {
position: absolute;
right: 0;
inset-inline: 0;
bottom: 0;
left: 0;
z-index: 2;
display: flex;
justify-content: center;
padding: 0;
// Use the .carousel-control's width as margin so we don't overlay those
margin-right: $carousel-control-width;
margin-inline-end: $carousel-control-width;
margin-bottom: 1rem;
margin-left: $carousel-control-width;
margin-inline-start: $carousel-control-width;
[data-bs-target],
[data-target] {
@@ -166,8 +167,8 @@
width: $carousel-indicator-width;
height: $carousel-indicator-height;
padding: 0;
margin-right: $carousel-indicator-spacer;
margin-left: $carousel-indicator-spacer;
margin-inline-end: $carousel-indicator-spacer;
margin-inline-start: $carousel-indicator-spacer;
text-indent: -999px;
cursor: pointer;
background-color: var(--#{$prefix}carousel-indicator-active-bg);
@@ -191,9 +192,8 @@
.carousel-caption {
position: absolute;
right: (100% - $carousel-caption-width) * 0.5;
inset-inline: (100% - $carousel-caption-width) * 0.5;
bottom: $carousel-caption-spacer;
left: (100% - $carousel-caption-width) * 0.5;
padding-top: $carousel-caption-padding-y;
padding-bottom: $carousel-caption-padding-y;
color: var(--#{$prefix}carousel-caption-color);
+12 -12
View File
@@ -58,7 +58,7 @@
margin: 0; // Override default margin of ul
@include font-size(var(--#{$prefix}dropdown-font-size));
color: var(--#{$prefix}dropdown-color);
text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
text-align: start; // Ensures proper alignment if parent has it changed (e.g., modal footer)
list-style: none;
background-color: var(--#{$prefix}dropdown-bg);
background-clip: padding-box;
@@ -69,7 +69,7 @@
&[data-bs-popper],
&[data-tblr-popper] {
top: 100%;
left: 0;
inset-inline-start: 0;
margin-top: var(--#{$prefix}dropdown-spacer);
}
@@ -98,8 +98,8 @@
&[data-bs-popper],
&[data-tblr-popper] {
right: auto;
left: 0;
inset-inline-end: auto;
inset-inline-start: 0;
}
}
@@ -108,8 +108,8 @@
&[data-bs-popper],
&[data-tblr-popper] {
right: 0;
left: auto;
inset-inline-end: 0;
inset-inline-start: auto;
}
}
}
@@ -136,10 +136,10 @@
.dropdown-menu[data-bs-popper],
.dropdown-menu[data-tblr-popper] {
top: 0;
right: auto;
left: 100%;
inset-inline-end: auto;
inset-inline-start: 100%;
margin-top: 0;
margin-left: var(--#{$prefix}dropdown-spacer);
margin-inline-start: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
@@ -154,10 +154,10 @@
.dropdown-menu[data-bs-popper],
.dropdown-menu[data-tblr-popper] {
top: 0;
right: 100%;
left: auto;
inset-inline-end: 100%;
inset-inline-start: auto;
margin-top: 0;
margin-right: var(--#{$prefix}dropdown-spacer);
margin-inline-end: var(--#{$prefix}dropdown-spacer);
}
.dropdown-toggle {
+4 -4
View File
@@ -31,7 +31,7 @@
flex-direction: column;
// No need to set list-style: none; since .list-group-item is block level
padding-left: 0; // reset padding because ul and ol
padding-inline-start: 0; // reset padding because ul and ol
margin-bottom: 0;
@include border-radius(var(--#{$prefix}list-group-border-radius));
}
@@ -149,11 +149,11 @@
+ .list-group-item {
border-top-width: var(--#{$prefix}list-group-border-width);
border-left-width: 0;
border-inline-start-width: 0;
&.active {
margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
border-left-width: var(--#{$prefix}list-group-border-width);
margin-inline-start: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
border-inline-start-width: var(--#{$prefix}list-group-border-width);
}
}
}
+5 -5
View File
@@ -36,8 +36,8 @@
// scss-docs-end modal-css-vars
position: fixed;
inset-inline-start: 0;
top: 0;
left: 0;
z-index: var(--#{$prefix}modal-zindex);
display: none;
width: 100%;
@@ -137,9 +137,9 @@
padding: calc(var(--#{$prefix}modal-header-padding-y) * 0.5) calc(var(--#{$prefix}modal-header-padding-x) * 0.5);
// Split properties to avoid invalid calc() function if value is 0
margin-top: calc(-0.5 * var(--#{$prefix}modal-header-padding-y));
margin-right: calc(-0.5 * var(--#{$prefix}modal-header-padding-x));
margin-inline-end: calc(-0.5 * var(--#{$prefix}modal-header-padding-x));
margin-bottom: calc(-0.5 * var(--#{$prefix}modal-header-padding-y));
margin-left: auto;
margin-inline-start: auto;
}
}
@@ -189,8 +189,8 @@
// Automatically set modal's width for larger viewports
.modal-dialog {
max-width: var(--#{$prefix}modal-width);
margin-right: auto;
margin-left: auto;
margin-inline-end: auto;
margin-inline-start: auto;
}
.modal-sm {
+3 -3
View File
@@ -18,7 +18,7 @@
display: flex;
flex-wrap: wrap;
padding-left: 0;
padding-inline-start: 0;
margin-bottom: 0;
list-style: none;
}
@@ -135,8 +135,8 @@
gap: var(--#{$prefix}nav-underline-gap);
.nav-link {
padding-right: 0;
padding-left: 0;
padding-inline-end: 0;
padding-inline-start: 0;
border-bottom: var(--#{$prefix}nav-underline-border-width) solid transparent;
&:hover,
+4 -4
View File
@@ -68,7 +68,7 @@
.navbar-brand {
padding-top: var(--#{$prefix}navbar-brand-padding-y);
padding-bottom: var(--#{$prefix}navbar-brand-padding-y);
margin-right: var(--#{$prefix}navbar-brand-margin-end);
margin-inline-end: var(--#{$prefix}navbar-brand-margin-end);
@include font-size(var(--#{$prefix}navbar-brand-font-size));
color: var(--#{$prefix}navbar-brand-color);
text-decoration: if(sass($link-decoration == none): null; else: none);
@@ -98,7 +98,7 @@
display: flex;
flex-direction: column; // cannot use `inherit` to get the `.navbar`s value
padding-left: 0;
padding-inline-start: 0;
margin-bottom: 0;
list-style: none;
@@ -208,8 +208,8 @@
}
.nav-link {
padding-right: var(--#{$prefix}navbar-nav-link-padding-x);
padding-left: var(--#{$prefix}navbar-nav-link-padding-x);
padding-inline-end: var(--#{$prefix}navbar-nav-link-padding-x);
padding-inline-start: var(--#{$prefix}navbar-nav-link-padding-x);
}
}
+12 -12
View File
@@ -52,24 +52,25 @@
&.offcanvas-start {
top: 0;
left: 0;
inset-inline-start: 0;
width: var(--#{$prefix}offcanvas-width);
border-right: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateX(-100%);
border-inline-end: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -100%));
}
&.offcanvas-end {
top: 0;
right: 0;
inset-inline-end: 0;
width: var(--#{$prefix}offcanvas-width);
border-left: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
transform: translateX(100%);
border-inline-start: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * 100%));
}
&.offcanvas-top {
top: 0;
right: 0;
left: 0;
inset-inline: 0;
height: var(--#{$prefix}offcanvas-height);
max-height: 100%;
border-bottom: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
@@ -77,8 +78,7 @@
}
&.offcanvas-bottom {
right: 0;
left: 0;
inset-inline: 0;
height: var(--#{$prefix}offcanvas-height);
max-height: 100%;
border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color);
@@ -133,9 +133,9 @@
padding: calc(var(--#{$prefix}offcanvas-padding-y) * 0.5) calc(var(--#{$prefix}offcanvas-padding-x) * 0.5);
// Split properties to avoid invalid calc() function if value is 0
margin-top: calc(-0.5 * var(--#{$prefix}offcanvas-padding-y));
margin-right: calc(-0.5 * var(--#{$prefix}offcanvas-padding-x));
margin-inline-end: calc(-0.5 * var(--#{$prefix}offcanvas-padding-x));
margin-bottom: calc(-0.5 * var(--#{$prefix}offcanvas-padding-y));
margin-left: auto;
margin-inline-start: auto;
}
}
+1 -1
View File
@@ -74,7 +74,7 @@
.page-item {
&:not(:first-child) .page-link {
margin-left: $pagination-margin-start;
margin-inline-start: $pagination-margin-start;
}
@if $pagination-margin-start == calc(-1 * #{$pagination-border-width}) {
+2 -2
View File
@@ -127,10 +127,10 @@
.popover-header::before {
position: absolute;
top: 0;
left: 50%;
inset-inline-start: 50%;
display: block;
width: var(--#{$prefix}popover-arrow-width);
margin-left: calc(-0.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list
margin-inline-start: calc(-0.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list
content: '';
border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);
}
+4 -4
View File
@@ -150,7 +150,7 @@ address {
ol,
ul {
padding-left: 2rem;
padding-inline-start: 2rem;
}
ol,
@@ -175,7 +175,7 @@ dt {
dd {
margin-bottom: 0.5rem;
margin-left: 0; // 1
margin-inline-start: 0; // 1
}
// Blockquote
@@ -337,7 +337,7 @@ caption {
padding-top: $table-cell-padding-y;
padding-bottom: $table-cell-padding-y;
color: $table-caption-color;
text-align: left;
text-align: start;
}
// 1. Removes font-weight bold by inheriting
@@ -480,7 +480,7 @@ fieldset {
// See https://github.com/twbs/bootstrap/issues/29712
legend {
float: left; // 1
float: inline-start; // 1
width: 100%;
padding: 0;
margin-bottom: $legend-margin-bottom;
+2 -2
View File
@@ -64,8 +64,8 @@
@include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width)));
.btn-close {
margin-right: calc(-0.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list
margin-left: var(--#{$prefix}toast-padding-x);
margin-inline-end: calc(-0.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list
margin-inline-start: var(--#{$prefix}toast-padding-x);
}
}
+1 -1
View File
@@ -45,7 +45,7 @@
display: inline-block;
&:not(:last-child) {
margin-right: $list-inline-padding;
margin-inline-end: $list-inline-padding;
}
}
@@ -14,7 +14,7 @@
> label {
position: absolute;
top: 0;
left: 0;
inset-inline-start: 0;
z-index: 2;
max-width: 100%;
height: 100%; // allow textareas
@@ -53,7 +53,7 @@
> .form-select {
padding-top: $form-floating-input-padding-t;
padding-bottom: $form-floating-input-padding-b;
padding-left: $form-floating-padding-x;
padding-inline-start: $form-floating-padding-x;
}
> .form-control:focus,
+16 -16
View File
@@ -7,24 +7,24 @@
.form-check {
display: block;
min-height: $form-check-min-height;
padding-left: $form-check-padding-start;
padding-inline-start: $form-check-padding-start;
margin-bottom: $form-check-margin-bottom;
.form-check-input {
float: left;
margin-left: $form-check-padding-start * -1;
float: inline-start;
margin-inline-start: $form-check-padding-start * -1;
}
}
.form-check-reverse {
padding-right: $form-check-padding-start;
padding-left: 0;
text-align: right;
padding-inline-end: $form-check-padding-start;
padding-inline-start: 0;
text-align: end;
.form-check-input {
float: right;
margin-right: $form-check-padding-start * -1;
margin-left: 0;
float: inline-end;
margin-inline-end: $form-check-padding-start * -1;
margin-inline-start: 0;
}
}
@@ -124,13 +124,13 @@
//
.form-switch {
padding-left: $form-switch-padding-start;
padding-inline-start: $form-switch-padding-start;
.form-check-input {
--#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)};
width: $form-switch-width;
margin-left: $form-switch-padding-start * -1;
margin-inline-start: $form-switch-padding-start * -1;
background-image: var(--#{$prefix}form-switch-bg);
background-position: left center;
@include border-radius($form-switch-border-radius, 0);
@@ -152,19 +152,19 @@
}
&.form-check-reverse {
padding-right: $form-switch-padding-start;
padding-left: 0;
padding-inline-end: $form-switch-padding-start;
padding-inline-start: 0;
.form-check-input {
margin-right: $form-switch-padding-start * -1;
margin-left: 0;
margin-inline-end: $form-switch-padding-start * -1;
margin-inline-start: 0;
}
}
}
.form-check-inline {
display: inline-block;
margin-right: $form-check-inline-margin-end;
margin-inline-end: $form-check-inline-margin-end;
}
.btn-check {
+2 -2
View File
@@ -139,8 +139,8 @@
&.form-control-sm,
&.form-control-lg {
padding-right: 0;
padding-left: 0;
padding-inline-end: 0;
padding-inline-start: 0;
}
}
+3 -3
View File
@@ -40,7 +40,7 @@
&[multiple],
&[size]:not([size='1']) {
padding-right: $form-select-padding-x;
padding-inline-end: $form-select-padding-x;
background-image: none;
}
@@ -60,7 +60,7 @@
.form-select-sm {
padding-top: $form-select-padding-y-sm;
padding-bottom: $form-select-padding-y-sm;
padding-left: $form-select-padding-x-sm;
padding-inline-start: $form-select-padding-x-sm;
@include font-size($form-select-font-size-sm);
@include border-radius($form-select-border-radius-sm);
}
@@ -68,7 +68,7 @@
.form-select-lg {
padding-top: $form-select-padding-y-lg;
padding-bottom: $form-select-padding-y-lg;
padding-left: $form-select-padding-x-lg;
padding-inline-start: $form-select-padding-x-lg;
@include font-size($form-select-font-size-lg);
@include border-radius($form-select-border-radius-lg);
}
+2 -2
View File
@@ -92,7 +92,7 @@
.input-group-lg > .form-select,
.input-group-sm > .form-select {
padding-right: $form-select-padding-x + $form-select-indicator-padding;
padding-inline-end: $form-select-padding-x + $form-select-indicator-padding;
}
// Rounded corners
@@ -127,7 +127,7 @@
}
> :not(:first-child):not(.dropdown-menu)#{$validation-messages} {
margin-left: calc(-1 * #{$input-border-width}); // stylelint-disable-line function-disallowed-list
margin-inline-start: calc(-1 * #{$input-border-width}); // stylelint-disable-line function-disallowed-list
@include border-start-radius(0);
}
+2 -1
View File
@@ -122,7 +122,8 @@ Navbar
position: absolute;
top: 0.5rem;
inset-inline-end: 0.5rem;
transform: translate(50%, -50%);
/*rtl:ignore*/
transform: translate(calc(var(--#{$prefix}dir) * 50%), -50%);
}
}
}
+1 -1
View File
@@ -5,8 +5,8 @@
// Shared between modals and offcanvases
@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) {
position: fixed;
inset-inline-start: 0;
top: 0;
left: 0;
z-index: $zindex;
width: 100vw;
height: 100vh;
+8 -7
View File
@@ -4,29 +4,30 @@
@use 'breakpoints' as *;
@mixin caret-down($width: $caret-width) {
border-top: $width solid;
border-right: $width solid transparent;
border-inline-end: $width solid transparent;
border-bottom: 0;
border-left: $width solid transparent;
border-inline-start: $width solid transparent;
}
@mixin caret-up($width: $caret-width) {
border-top: 0;
border-right: $width solid transparent;
border-inline-end: $width solid transparent;
border-bottom: $width solid;
border-left: $width solid transparent;
border-inline-start: $width solid transparent;
}
@mixin caret-end($width: $caret-width) {
border-top: $width solid transparent;
border-right: 0;
border-inline-end: 0;
border-bottom: $width solid transparent;
border-left: $width solid;
border-inline-start: $width solid;
}
@mixin caret-start($width: $caret-width) {
border-top: $width solid transparent;
border-right: $width solid;
border-inline-end: $width solid;
border-bottom: $width solid transparent;
border-inline-start: 0;
}
@mixin caret($direction: down, $width: $caret-width, $spacing: $caret-spacing, $vertical-align: $caret-vertical-align) {
+4 -4
View File
@@ -8,8 +8,8 @@
--#{$prefix}gutter-x: #{$gutter};
--#{$prefix}gutter-y: 0;
width: 100%;
padding-right: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
margin-right: auto;
margin-left: auto;
padding-inline-end: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
padding-inline-start: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
margin-inline-end: auto;
margin-inline-start: auto;
}
+4 -4
View File
@@ -58,7 +58,7 @@
border-color: $border-color;
@if $enable-validation-icons {
padding-right: $input-height-inner;
padding-inline-end: $input-height-inner;
background-image: escape-svg($icon);
background-repeat: no-repeat;
background-position: right $input-height-inner-quarter center;
@@ -80,7 +80,7 @@
textarea.form-control {
@include form-validation-state-selector($state) {
@if $enable-validation-icons {
padding-right: $input-height-inner;
padding-inline-end: $input-height-inner;
background-position: top $input-height-inner-quarter right $input-height-inner-quarter;
}
}
@@ -94,7 +94,7 @@
&:not([multiple]):not([size]),
&:not([multiple])[size='1'] {
--#{$prefix}form-select-bg-icon: #{escape-svg($icon)};
padding-right: $form-select-feedback-icon-padding-end;
padding-inline-end: $form-select-feedback-icon-padding-end;
background-position: $form-select-bg-position, $form-select-feedback-icon-position;
background-size: $form-select-bg-size, $form-select-feedback-icon-size;
}
@@ -138,7 +138,7 @@
}
.form-check-inline .form-check-input {
~ .#{$state}-feedback {
margin-left: 0.5em;
margin-inline-start: 0.5em;
}
}
+5 -5
View File
@@ -17,8 +17,8 @@
display: flex;
flex-wrap: wrap;
margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list
margin-right: calc(-0.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-left: calc(-0.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-inline-end: calc(-0.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
margin-inline-start: calc(-0.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list
}
@mixin make-col-ready() {
@@ -26,8 +26,8 @@
flex-shrink: 0;
width: 100%;
max-width: 100%;
padding-right: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
padding-left: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
padding-inline-end: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
padding-inline-start: calc(var(--#{$prefix}gutter-x) * 0.5); // stylelint-disable-line function-disallowed-list
margin-top: var(--#{$prefix}gutter-y);
}
@@ -48,7 +48,7 @@
@mixin make-col-offset($size, $columns: $grid-columns) {
$num: divide($size, $columns);
margin-left: if(sass($num == 0): 0; else: math.percentage($num));
margin-inline-start: if(sass($num == 0): 0; else: math.percentage($num));
}
@mixin row-cols($count) {
+1 -1
View File
@@ -6,6 +6,6 @@
// Unstyled keeps list items block level, just removes default browser padding and list-style
@mixin list-unstyled {
padding-left: 0;
padding-inline-start: 0;
list-style: none;
}
+25 -5
View File
@@ -314,16 +314,26 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
@include rfs($value, padding-top);
}
@mixin padding-inline-end($value) {
@include rfs($value, padding-inline-end);
}
// Deprecated: use padding-inline-end() instead
@mixin padding-right($value) {
@include rfs($value, padding-right);
@include padding-inline-end($value);
}
@mixin padding-bottom($value) {
@include rfs($value, padding-bottom);
}
@mixin padding-inline-start($value) {
@include rfs($value, padding-inline-start);
}
// Deprecated: use padding-inline-start() instead
@mixin padding-left($value) {
@include rfs($value, padding-left);
@include padding-inline-start($value);
}
@mixin margin($value) {
@@ -334,14 +344,24 @@ $rfs-mq-property-height: if(sass($rfs-mode == max-media-query): max-height; else
@include rfs($value, margin-top);
}
@mixin margin-inline-end($value) {
@include rfs($value, margin-inline-end);
}
// Deprecated: use margin-inline-end() instead
@mixin margin-right($value) {
@include rfs($value, margin-right);
@include margin-inline-end($value);
}
@mixin margin-bottom($value) {
@include rfs($value, margin-bottom);
}
@mixin margin-left($value) {
@include rfs($value, margin-left);
@mixin margin-inline-start($value) {
@include rfs($value, margin-inline-start);
}
// Deprecated: use margin-inline-start() instead
@mixin margin-left($value) {
@include margin-inline-start($value);
}
+6 -5
View File
@@ -16,9 +16,9 @@
@include expect() {
.t {
border-top: 0.3em solid;
border-right: 0.3em solid transparent;
border-inline-end: 0.3em solid transparent;
border-bottom: 0;
border-left: 0.3em solid transparent;
border-inline-start: 0.3em solid transparent;
}
}
}
@@ -34,9 +34,9 @@
@include expect() {
.t {
border-top: 0;
border-right: 0.3em solid transparent;
border-inline-end: 0.3em solid transparent;
border-bottom: 0.3em solid;
border-left: 0.3em solid transparent;
border-inline-start: 0.3em solid transparent;
}
}
}
@@ -52,8 +52,9 @@
@include expect() {
.t {
border-top: 0.3em solid transparent;
border-right: 0.3em solid;
border-inline-end: 0.3em solid;
border-bottom: 0.3em solid transparent;
border-inline-start: 0;
}
}
}
+15 -11
View File
@@ -68,7 +68,7 @@
@include output() {
@include generate-utility(
(
property: margin-right margin-left,
property: margin-inline-end margin-inline-start,
class: mx,
values: (
0: 0,
@@ -79,12 +79,12 @@
}
@include expect() {
.mx-0 {
margin-right: 0 !important;
margin-left: 0 !important;
margin-inline-end: 0 !important;
margin-inline-start: 0 !important;
}
.mx-auto {
margin-right: auto !important;
margin-left: auto !important;
margin-inline-end: auto !important;
margin-inline-start: auto !important;
}
}
}
@@ -181,8 +181,9 @@
property: float,
class: float,
values: (
left,
right,
start: inline-start,
end: inline-end,
none: none,
),
),
);
@@ -209,11 +210,14 @@
.d-flex {
display: flex !important;
}
.float-left {
float: left !important;
.float-start {
float: inline-start !important;
}
.float-right {
float: right !important;
.float-end {
float: inline-end !important;
}
.float-none {
float: none !important;
}
// responsive breakpoints: only `d` (responsive: true) is repeated; `float` is not
+6 -6
View File
@@ -67,7 +67,7 @@
}
@include expect() {
.t {
margin-left: 25%;
margin-inline-start: 25%;
}
}
}
@@ -82,7 +82,7 @@
}
@include expect() {
.t {
margin-left: 0;
margin-inline-start: 0;
}
}
}
@@ -122,8 +122,8 @@
display: flex;
flex-wrap: wrap;
margin-top: calc(-1 * var(--tblr-gutter-y));
margin-right: calc(-0.5 * var(--tblr-gutter-x));
margin-left: calc(-0.5 * var(--tblr-gutter-x));
margin-inline-end: calc(-0.5 * var(--tblr-gutter-x));
margin-inline-start: calc(-0.5 * var(--tblr-gutter-x));
}
}
}
@@ -143,8 +143,8 @@
flex-shrink: 0;
width: 100%;
max-width: 100%;
padding-right: calc(var(--tblr-gutter-x) * 0.5);
padding-left: calc(var(--tblr-gutter-x) * 0.5);
padding-inline-end: calc(var(--tblr-gutter-x) * 0.5);
padding-inline-start: calc(var(--tblr-gutter-x) * 0.5);
margin-top: var(--tblr-gutter-y);
}
}
+2 -1
View File
@@ -83,7 +83,8 @@
position: absolute !important;
top: 0 !important;
inset-inline-end: 0 !important;
transform: translate(50%, -50%);
/*rtl:ignore*/
transform: translate(calc(var(--#{$prefix}dir) * 50%), -50%);
z-index: 1;
}
+4 -2
View File
@@ -315,7 +315,8 @@
&:hover,
&:focus-visible {
.icon {
transform: translateX(4px);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * 4px));
}
}
@@ -332,7 +333,8 @@
&:hover,
&:focus-visible {
.icon {
transform: translateX(-4px);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -4px));
}
}
}
+2 -9
View File
@@ -457,22 +457,15 @@ Card table
td,
th {
&:first-child {
padding-left: $card-spacer-x;
border-left: 0;
border-top-left-radius: var(--#{$prefix}card-border-radius);
}
&:last-child {
padding-right: $card-spacer-x;
border-right: 0;
border-top-right-radius: var(--#{$prefix}card-border-radius);
padding-inline-start: $card-spacer-x;
border-inline-start: 0;
border-start-start-radius: var(--#{$prefix}card-border-radius);
}
&:last-child {
padding-inline-end: $card-spacer-x;
border-inline-end: 0;
border-start-end-radius: var(--#{$prefix}card-border-radius);
}
}
}
+2 -1
View File
@@ -56,7 +56,8 @@ Dimmer
@keyframes animated-dots {
0% {
transform: translateX(-100%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -100%));
}
}
+5
View File
@@ -3,6 +3,7 @@
.signature {
--#{$prefix}signature-padding: var(--#{$prefix}spacer-1);
--#{$prefix}signature-border-radius: var(--#{$prefix}border-radius);
--#{$prefix}signature-canvas-height: 12.5rem;
border: var(--#{$prefix}border-width) solid var(--#{$prefix}border-color);
padding: var(--#{$prefix}signature-padding);
@include border-radius(var(--#{$prefix}border-radius));
@@ -14,4 +15,8 @@
display: block;
cursor: crosshair;
width: 100%;
// A fixed height is required: without it the canvas height comes from its own
// width/height attributes, which `resizeCanvas()` rewrites on every resize
// each run then measures a different `offsetHeight` and the pad drifts.
height: var(--#{$prefix}signature-canvas-height);
}
+4 -2
View File
@@ -83,7 +83,8 @@
align-items: center;
justify-content: center;
@include border-radius(var(--#{$prefix}border-radius-pill));
transform: translateX(-50%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -50%));
color: var(--#{$prefix}white);
width: var(--#{$prefix}steps-dot-size);
height: var(--#{$prefix}steps-dot-size);
@@ -157,7 +158,8 @@
&:after {
position: absolute;
content: '';
transform: translateX(-50%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -50%));
top: var(--#{$prefix}steps-dot-offset);
inset-inline-start: calc(var(--#{$prefix}steps-dot-size) * 0.5);
width: var(--#{$prefix}steps-border-width);
+8 -4
View File
@@ -161,12 +161,14 @@
}
.switch-icon-b {
transform: translateX(100%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * 100%));
}
&.active {
.switch-icon-a {
transform: translateX(-100%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -100%));
}
.switch-icon-b {
@@ -182,12 +184,14 @@
}
.switch-icon-b {
transform: translateX(-100%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * -100%));
}
&.active {
.switch-icon-a {
transform: translateX(100%);
/*rtl:ignore*/
transform: translateX(calc(var(--#{$prefix}dir) * 100%));
}
.switch-icon-b {
+18
View File
@@ -73,6 +73,24 @@ Add a status color to your card, either at the top or on the side of the card, t
<div class="row row-deck"> <div class="col-md-6"> <div class="card"> <div class="card-status-top bg-danger"></div> <div class="card-body"> <h3 class="card-title">Card with top status</h3> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p> </div> </div> </div> <div class="col-md-6"> <div class="card"> <div class="card-status-start bg-green"></div> <div class="card-body"> <h3 class="card-title">Card with side status</h3> <p class="text-secondary"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur perferendis sed suscipit velit vitae voluptatem. </p> </div> </div> </div> </div>
</Example>
## Card stamp
Use a card stamp to put a large, faded icon in the top corner of a card. It is only a decoration, so it never covers the text and it does not react to clicks.
Add a `.card-stamp` element as a direct child of the card, before the card body. Put the icon in a `.card-stamp-icon` element inside it.
<Example bg="surface-secondary" column>
<div class="card"> <div class="card-stamp"> <div class="card-stamp-icon bg-yellow"> <Icon name="bell" /> </div> </div> <div class="card-body"> <h3 class="card-title">Card with a stamp</h3> <p class="text-secondary">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aperiam deleniti fugit incidunt, iste, itaque minima neque pariatur.</p> </div> </div>
</Example>
## Card stamp size and color
Add the `card-stamp-lg` class to make the stamp bigger. Change the circle color with a `bg-*` class, and the icon color with a `text-*` class.
<Example bg="surface-secondary">
<div class="row row-deck"> <div class="col-md-6"> <div class="card"> <div class="card-stamp card-stamp-lg"> <div class="card-stamp-icon bg-primary"> <Icon name="ghost" /> </div> </div> <div class="card-body"> <h3 class="card-title">Large stamp</h3> <p class="text-secondary">The large stamp is a good fit for banners and wide cards.</p> </div> </div> </div> <div class="col-md-6"> <div class="card bg-primary text-primary-fg"> <div class="card-stamp"> <div class="card-stamp-icon bg-white text-primary"> <Icon name="star" /> </div> </div> <div class="card-body"> <h3 class="card-title">Stamp on a color card</h3> <p>Use a white circle with a colored icon on a card with a background color.</p> </div> </div> </div> </div>
</Example>
## Stacked card
Use the `card-stacked` class to stack up multiple cards, if you want to save screen space or create a visually appealing effect.
+118
View File
@@ -0,0 +1,118 @@
---
title: Map
summary: A map shows places and markers on an interactive world map. Tabler provides the markup and the setup code, and the map itself is rendered by Mapbox GL JS.
description: Show places on an interactive map.
layout: '@layouts/DocsMdxLayout.astro'
---
import Example from '@components/Example.astro';
import { Code } from 'astro:components';
## Overview
The map is a small wrapper around [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/). Tabler gives you the container markup and a short init script. Mapbox draws the tiles, handles zoom, and renders the markers.
A Mapbox account and an access token are needed, because every map load calls the Mapbox API. If you only need a simple map of countries or regions, use the [vector map](/ui/components/vector-map/) instead. It needs no account and no network calls.
## Installation
Add the Mapbox GL JS script and stylesheet to your page. Tabler uses version 1.8.0:
<Code
lang="html"
code={`<link href="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.css" rel="stylesheet" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>`}
/>
Then create a free account on [mapbox.com](https://www.mapbox.com/) and copy your public access token. It starts with `pk.`. Set it once, before you create a map:
```js
mapboxgl.accessToken = 'pk.your-token-here'
```
Use a public token only. A secret token (`sk.`) must never be sent to the browser. Limit the token to your own domains in the Mapbox dashboard.
## Usage
### Markup
Put the map container inside a `ratio` element, so the map keeps its shape on every screen size. Give the inner element an `id` and the `w-100 h-100` classes.
<Example codeOnly>
<div class="ratio ratio-16x9"> <div> <div id="map-simple" class="w-100 h-100"></div> </div> </div>
</Example>
Change the shape with the ratio classes, for example `ratio-21x9` for a wide map or `ratio-1x1` for a square one.
### Init the map
Create the map after the DOM is ready. Pass the id of your container, a style, a zoom level, and a center point.
```js
document.addEventListener('DOMContentLoaded', function () {
mapboxgl.accessToken = 'pk.your-token-here'
const map = new mapboxgl.Map({
container: 'map-simple',
style: 'mapbox://styles/mapbox/streets-v11',
zoom: 13,
center: [13.4049, 52.518827],
})
})
```
`center` takes the longitude first and the latitude second. This is the Mapbox order, and it is the opposite of what most map services show.
### Map styles
Set `style` to any Mapbox style URL. These three are used in the Tabler demos:
| Style | Result |
| --- | --- |
| `mapbox://styles/mapbox/streets-v11` | Default street map. |
| `mapbox://styles/mapbox/light-v10` | Light map, good under charts and markers. |
| `mapbox://styles/mapbox/satellite-v9` | Satellite photos. |
### Markers
Add a marker for each place. `setLngLat` takes the same longitude and latitude order as `center`.
```js
const cities = [
[-58.666667, -34.58333333], // Buenos Aires
[16.366667, 48.2], // Vienna
[116.383333, 39.91666667], // Beijing
]
cities.forEach(function (coords) {
new mapboxgl.Marker({ color: 'var(--tblr-primary)' }).setLngLat(coords).addTo(map)
})
```
The `color` option is written to the `fill` attribute of the marker icon. A CSS variable works there, so `var(--tblr-primary)` keeps the markers in your theme color, including after a theme change.
## Examples
### Map in a card
Add a card title above the map. This is the usual layout for a small map next to other content.
<Example codeOnly>
<div class="card"> <div class="card-body"> <div class="card-title">Simple map</div> <div class="ratio ratio-16x9"> <div> <div id="map-card" class="w-100 h-100"></div> </div> </div> </div> </div>
</Example>
### Full-card map
Drop the card body to let the map fill the whole card. Add `rounded` to the container, so the map follows the card corners.
<Example codeOnly>
<div class="card"> <div class="ratio ratio-21x9"> <div> <div id="map-full" class="w-100 h-100 rounded"></div> </div> </div> </div>
</Example>
Live versions of these maps are on the [maps preview page](https://preview.tabler.io/maps.html).
## Accessibility
- The map is a picture for most users. Give the same information as text near it, for example the address or a list of places.
- Add an `aria-label` to the map container, so screen reader users know what the map shows.
- Do not put an action only on a marker. Repeat it in a normal link or button below the map.
- Keep a visible fallback when the script fails to load, for example the address in text.
+82
View File
@@ -0,0 +1,82 @@
---
title: Trending
summary: A trend indicator shows how a value changed. It joins the number with an arrow and a color, so users can read the direction at a glance.
description: Show value change with a trend indicator.
layout: '@layouts/DocsMdxLayout.astro'
---
import Example from '@components/Example.astro';
import Icon from '@ui/Icon.astro';
## Overview
A trend indicator is a small inline element. It shows a number and an arrow next to it. Use it next to a metric, in a stats card, or in a table row.
There is no dedicated class for it. Build it from utilities: `d-inline-flex` and `align-items-center` to keep the number and the icon in one line, `lh-1` to keep the line short, and a text color that matches the direction.
<Example centered>
<span class="text-green d-inline-flex align-items-center lh-1">25% <Icon name="arrow-up" size="sm" class="ms-0" /></span>
</Example>
## Variants
### Direction
Use three states to describe the change. Pick the color and the icon together, so they always tell the same story.
| Change | Color | Icon |
| --- | --- | --- |
| Up | `text-green` | `arrow-up` |
| No change | `text-muted` | `minus` |
| Down | `text-red` | `arrow-down` |
<Example centered>
<span class="text-green d-inline-flex align-items-center lh-1">25% <Icon name="arrow-up" size="sm" class="ms-0" /></span> <span class="text-muted d-inline-flex align-items-center lh-1">0% <Icon name="minus" size="sm" class="ms-0" /></span> <span class="text-red d-inline-flex align-items-center lh-1">-12% <Icon name="arrow-down" size="sm" class="ms-0" /></span>
</Example>
### Unit
The unit is only text after the number. Use a percent sign, a currency, or no unit at all.
<Example centered>
<span class="text-green d-inline-flex align-items-center lh-1">8% <Icon name="arrow-up" size="sm" class="ms-0" /></span> <span class="text-green d-inline-flex align-items-center lh-1">4.2K <Icon name="arrow-up" size="sm" class="ms-0" /></span> <span class="text-red d-inline-flex align-items-center lh-1">-3 <Icon name="arrow-down" size="sm" class="ms-0" /></span>
</Example>
### Size
The indicator takes the font size of its parent. Put it in a heading or use a text size utility to make it bigger or smaller.
<Example centered vertical>
<span class="text-green d-inline-flex align-items-center lh-1 small">15% <Icon name="arrow-up" size="sm" class="ms-0" /></span> <span class="text-green d-inline-flex align-items-center lh-1">15% <Icon name="arrow-up" size="sm" class="ms-0" /></span> <span class="text-green d-inline-flex align-items-center lh-1 h2 m-0">15% <Icon name="arrow-up" class="ms-0" /></span>
</Example>
## Examples
### Next to a value
Place the indicator after the number. Use `align-items-baseline` on the wrapper, so the number and the indicator sit on the same line.
<Example>
<div> <div class="text-secondary">Today's sales</div> <div class="d-flex align-items-baseline"> <div class="h3 me-2 mb-0">6,782</div> <span class="text-green d-inline-flex align-items-center lh-1">7% <Icon name="arrow-up" size="sm" class="ms-0" /></span> </div> </div>
</Example>
### In a stats card
This is the most common place for the indicator. The value stays on the left and the change on the right.
<Example bg="surface-secondary" column>
<div class="card"> <div class="card-body"> <div class="row align-items-center"> <div class="col"> <div class="text-secondary">New clients</div> <div class="h3 m-0">1,352</div> </div> <div class="col-auto"> <span class="text-red d-inline-flex align-items-center lh-1">-4% <Icon name="arrow-down" size="sm" class="ms-0" /></span> </div> </div> </div> </div>
</Example>
### In a table
Use it in a table cell to compare rows quickly.
<Example>
<table class="table"> <thead> <tr> <th>Product</th> <th>Sales</th> <th>Change</th> </tr> </thead> <tbody> <tr> <td>Basic plan</td> <td>4,120</td> <td><span class="text-green d-inline-flex align-items-center lh-1">12% <Icon name="arrow-up" size="sm" class="ms-0" /></span></td> </tr> <tr> <td>Pro plan</td> <td>2,043</td> <td><span class="text-red d-inline-flex align-items-center lh-1">-7% <Icon name="arrow-down" size="sm" class="ms-0" /></span></td> </tr> <tr> <td>Team plan</td> <td>986</td> <td><span class="text-muted d-inline-flex align-items-center lh-1">0% <Icon name="minus" size="sm" class="ms-0" /></span></td> </tr> </tbody> </table>
</Example>
## Accessibility
- Keep the sign in the text, for example `-12%`. Users who do not see color still get the direction.
- The icon is hidden from screen readers, so it must not be the only carrier of meaning.
- Add a word like `Change` in the table header or near the value, so it is clear what the number means.
+8
View File
@@ -235,6 +235,10 @@
{
"title": "List group",
"url": "/ui/components/list-group/"
},
{
"title": "Map",
"url": "/ui/components/map/"
},
{
"title": "Modal",
@@ -324,6 +328,10 @@
"title": "Tracking",
"url": "/ui/components/tracking/"
},
{
"title": "Trending",
"url": "/ui/components/trending/"
},
{
"title": "Vector Map",
"url": "/ui/components/vector-map/"
+2 -4
View File
@@ -50,8 +50,6 @@ ${clearSnippet}
function resizeCanvas() {
const ratio = Math.max(window.devicePixelRatio || 1, 1);
console.log(canvas.offsetWidth, canvas.offsetHeight);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext("2d").scale(ratio, ratio);
@@ -72,9 +70,9 @@ ${extraSnippet}
{
clear && (
<div class="position-absolute top-0 end-0 p-2">
<div class="btn btn-icon" id={`signature-${id}-clear`} title="Clear signature" data-bs-toggle="tooltip">
<button type="button" class="btn btn-icon" id={`signature-${id}-clear`} title="Clear signature" data-bs-toggle="tooltip">
<Icon name="trash" />{' '}
</div>
</button>
</div>
)
}