mirror of
https://github.com/twbs/bootstrap.git
synced 2025-07-03 00:02:25 -04:00
Compare commits
13 Commits
8295fa1ebd
...
4285e9e22b
Author | SHA1 | Date | |
---|---|---|---|
|
4285e9e22b | ||
|
f96aa4cbc0 | ||
|
b02d5ed72f | ||
|
64b340c37f | ||
|
9566444580 | ||
|
c5074c7c18 | ||
|
879d1d15dc | ||
|
7d12ff7b3b | ||
|
9fce97c4b2 | ||
|
aecf990fc5 | ||
|
9d2fb4967b | ||
|
446c741800 | ||
|
7df0cdc2b6 |
663
package-lock.json
generated
663
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@ -113,9 +113,9 @@
|
|||||||
"@astrojs/mdx": "^4.3.0",
|
"@astrojs/mdx": "^4.3.0",
|
||||||
"@astrojs/prism": "^3.3.0",
|
"@astrojs/prism": "^3.3.0",
|
||||||
"@astrojs/sitemap": "^3.4.1",
|
"@astrojs/sitemap": "^3.4.1",
|
||||||
"@babel/cli": "^7.27.2",
|
"@babel/cli": "^7.28.0",
|
||||||
"@babel/core": "^7.27.7",
|
"@babel/core": "^7.28.0",
|
||||||
"@babel/preset-env": "^7.27.2",
|
"@babel/preset-env": "^7.28.0",
|
||||||
"@docsearch/js": "^3.9.0",
|
"@docsearch/js": "^3.9.0",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@rollup/plugin-babel": "^6.0.4",
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
@ -126,7 +126,7 @@
|
|||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/mime": "^4.0.0",
|
"@types/mime": "^4.0.0",
|
||||||
"@types/prismjs": "^1.26.5",
|
"@types/prismjs": "^1.26.5",
|
||||||
"astro": "^5.10.1",
|
"astro": "^5.10.2",
|
||||||
"astro-auto-import": "^0.4.4",
|
"astro-auto-import": "^0.4.4",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"bundlewatch": "^0.4.1",
|
"bundlewatch": "^0.4.1",
|
||||||
@ -180,7 +180,7 @@
|
|||||||
"terser": "^5.43.1",
|
"terser": "^5.43.1",
|
||||||
"unist-util-visit": "^5.0.0",
|
"unist-util-visit": "^5.0.0",
|
||||||
"vnu-jar": "24.10.17",
|
"vnu-jar": "24.10.17",
|
||||||
"zod": "^3.25.67"
|
"zod": "^3.25.69"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist/{css,js}/*.{css,js,map}",
|
"dist/{css,js}/*.{css,js,map}",
|
||||||
|
@ -157,7 +157,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
|
|||||||
|
|
||||||
@each $color in $foregrounds {
|
@each $color in $foregrounds {
|
||||||
$contrast-ratio: contrast-ratio($background, $color);
|
$contrast-ratio: contrast-ratio($background, $color);
|
||||||
@if $contrast-ratio > $min-contrast-ratio {
|
@if $contrast-ratio >= $min-contrast-ratio {
|
||||||
@return $color;
|
@return $color;
|
||||||
} @else if $contrast-ratio > $max-ratio {
|
} @else if $contrast-ratio > $max-ratio {
|
||||||
$max-ratio: $contrast-ratio;
|
$max-ratio: $contrast-ratio;
|
||||||
|
@ -375,6 +375,14 @@ th {
|
|||||||
border-width: 0;
|
border-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Contenteditable
|
||||||
|
//
|
||||||
|
// Handle focus states for elements with contenteditable set to true or plaintext-only
|
||||||
|
|
||||||
|
[contenteditable]:not([contenteditable="false"]):focus {
|
||||||
|
outline: 0;
|
||||||
|
box-shadow: $input-focus-box-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
// Forms
|
// Forms
|
||||||
//
|
//
|
||||||
|
139
scss/tests/mixins/_color-contrast.test.scss
Normal file
139
scss/tests/mixins/_color-contrast.test.scss
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
@import "../../functions";
|
||||||
|
@import "../../variables";
|
||||||
|
@import "../../variables-dark";
|
||||||
|
@import "../../maps";
|
||||||
|
@import "../../mixins";
|
||||||
|
|
||||||
|
@include describe("color-contrast function") {
|
||||||
|
@include it("should return a color when contrast ratio equals minimum requirement (WCAG 2.1 compliance)") {
|
||||||
|
// Test case: Background color that produces contrast ratio close to 4.5:1
|
||||||
|
// This tests the WCAG 2.1 requirement that contrast should be "at least 4.5:1" (>= 4.5)
|
||||||
|
// rather than "strictly greater than 4.5:1" (> 4.5)
|
||||||
|
|
||||||
|
// #777777 produces 4.4776:1 contrast ratio with white text
|
||||||
|
// Since this is below the 4.5:1 threshold, it should return the highest available contrast color
|
||||||
|
$test-background: #777;
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
|
||||||
|
@include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4776:1 contrast ratio (below threshold)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should return a color when contrast ratio is above minimum requirement") {
|
||||||
|
// Test case: Background color that produces contrast ratio above 4.5:1
|
||||||
|
// #767676 produces 4.5415:1 contrast ratio with white text
|
||||||
|
$test-background: #767676;
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
|
||||||
|
@include assert-equal($result, $white, "Should return white for background with 4.5415:1 contrast ratio (above threshold)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should return a color when contrast ratio is below minimum requirement") {
|
||||||
|
// Test case: Background color that produces contrast ratio below 4.5:1
|
||||||
|
// #787878 produces 4.4155:1 contrast ratio with white text
|
||||||
|
$test-background: #787878;
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
|
||||||
|
// Should return the color with the highest available contrast ratio
|
||||||
|
@include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4155:1 contrast ratio (below threshold)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should handle edge case with very light background") {
|
||||||
|
// Test case: Very light background that should return dark text
|
||||||
|
$test-background: #f8f9fa; // Very light gray
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
|
||||||
|
@include assert-equal($result, $color-contrast-dark, "Should return dark text for very light background");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should handle edge case with very dark background") {
|
||||||
|
// Test case: Very dark background that should return light text
|
||||||
|
$test-background: #212529; // Very dark gray
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
|
||||||
|
@include assert-equal($result, $color-contrast-light, "Should return light text for very dark background");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should work with custom minimum contrast ratio") {
|
||||||
|
// Test case: Using a custom minimum contrast ratio
|
||||||
|
$test-background: #666;
|
||||||
|
$result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, 3);
|
||||||
|
|
||||||
|
@include assert-equal($result, $white, "Should return white when using custom minimum contrast ratio of 3.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should test contrast ratio calculation accuracy") {
|
||||||
|
// Test case: Verify that contrast-ratio function works correctly
|
||||||
|
$background: #767676;
|
||||||
|
$foreground: $white;
|
||||||
|
$ratio: contrast-ratio($background, $foreground);
|
||||||
|
// Bootstrap's implementation calculates this as ~4.5415, not exactly 4.5, due to its luminance math.
|
||||||
|
// We use 4.54 as the threshold for this test to match the actual implementation.
|
||||||
|
@include assert-true($ratio >= 4.54 and $ratio <= 4.55, "Contrast ratio should be approximately 4.54:1 (Bootstrap's math)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should test luminance calculation") {
|
||||||
|
// Test case: Verify luminance function works correctly
|
||||||
|
$white-luminance: luminance($white);
|
||||||
|
$black-luminance: luminance($black);
|
||||||
|
|
||||||
|
@include assert-equal($white-luminance, 1, "White should have luminance of 1");
|
||||||
|
@include assert-equal($black-luminance, 0, "Black should have luminance of 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should handle rgba colors correctly") {
|
||||||
|
// Test case: Test with rgba colors
|
||||||
|
$test-background: rgba(118, 118, 118, 1); // Same as #767676
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
|
||||||
|
@include assert-equal($result, $white, "Should handle rgba colors correctly");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should test the WCAG 2.1 boundary condition with color below threshold") {
|
||||||
|
// Test case: Background color that produces contrast ratio below 4.5:1
|
||||||
|
// #787878 produces 4.4155:1 contrast ratio with white
|
||||||
|
$test-background: #787878; // Produces 4.4155:1 contrast ratio
|
||||||
|
$contrast-ratio: contrast-ratio($test-background, $white);
|
||||||
|
|
||||||
|
// Verify the contrast ratio is below 4.5:1
|
||||||
|
@include assert-true($contrast-ratio < 4.5, "Contrast ratio should be below 4.5:1 threshold");
|
||||||
|
|
||||||
|
// The color-contrast function should return the color with highest available contrast
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
@include assert-equal($result, $black, "color-contrast should return black (highest available contrast) for below-threshold ratio");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should test the WCAG 2.1 boundary condition with color at threshold") {
|
||||||
|
// Test case: Background color that produces contrast ratio close to 4.5:1
|
||||||
|
// #777777 produces 4.4776:1 contrast ratio with white
|
||||||
|
$test-background: #777; // Produces 4.4776:1 contrast ratio
|
||||||
|
$contrast-ratio: contrast-ratio($test-background, $white);
|
||||||
|
|
||||||
|
// Verify the contrast ratio is below 4.5:1 threshold
|
||||||
|
@include assert-true($contrast-ratio < 4.5, "Contrast ratio is below threshold, function should handle gracefully");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should demonstrate the difference between > and >= operators") {
|
||||||
|
// Test case: Demonstrates the difference between > and >= operators
|
||||||
|
// Uses #767676 with a custom minimum contrast ratio that matches its actual ratio (4.5415)
|
||||||
|
// With > 4.5415: should return black (fallback to highest available)
|
||||||
|
// With >= 4.5415: should return white (meets threshold)
|
||||||
|
|
||||||
|
$test-background: #767676; // Produces 4.5415:1 contrast ratio
|
||||||
|
$actual-ratio: contrast-ratio($test-background, $white);
|
||||||
|
|
||||||
|
// Test with a custom minimum that matches the actual ratio
|
||||||
|
$result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, $actual-ratio);
|
||||||
|
|
||||||
|
// Should return white when using >= implementation
|
||||||
|
@include assert-equal($result, $white, "color-contrast should return white when using exact ratio as threshold (>= implementation)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@include it("should test additional working colors above threshold") {
|
||||||
|
// Test case: Background color that produces contrast ratio well above 4.5:1
|
||||||
|
// #757575 produces 4.6047:1 contrast ratio with white text
|
||||||
|
$test-background: #757575; // Produces 4.6047:1 contrast ratio
|
||||||
|
$result: color-contrast($test-background);
|
||||||
|
|
||||||
|
@include assert-equal($result, $white, "Should return white for background with 4.6047:1 contrast ratio (well above threshold)");
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ import Stylesheet from '@components/head/Stylesheet.astro'
|
|||||||
import Favicons from '@components/head/Favicons.astro'
|
import Favicons from '@components/head/Favicons.astro'
|
||||||
import Social from '@components/head/Social.astro'
|
import Social from '@components/head/Social.astro'
|
||||||
import Analytics from '@components/head/Analytics.astro'
|
import Analytics from '@components/head/Analytics.astro'
|
||||||
import Scss from '@components/head/Scss.astro'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
description: string
|
description: string
|
||||||
@ -25,6 +24,10 @@ const isHome = Astro.url.pathname === '/'
|
|||||||
const pageTitle = isHome
|
const pageTitle = isHome
|
||||||
? `${getConfig().title} · ${getConfig().subtitle}`
|
? `${getConfig().title} · ${getConfig().subtitle}`
|
||||||
: `${title} · ${getConfig().title} v${getConfig().docs_version}`
|
: `${title} · ${getConfig().title} v${getConfig().docs_version}`
|
||||||
|
|
||||||
|
// Dynamic imports to avoid build-time processing
|
||||||
|
const Scss = import.meta.env.PROD ? null : await import('@components/head/Scss.astro')
|
||||||
|
const ScssProd = import.meta.env.PROD ? await import('@components/head/ScssProd.astro') : null
|
||||||
---
|
---
|
||||||
|
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
@ -47,8 +50,15 @@ const pageTitle = isHome
|
|||||||
|
|
||||||
<script is:inline src={getVersionedDocsPath('assets/js/color-modes.js')}></script>
|
<script is:inline src={getVersionedDocsPath('assets/js/color-modes.js')}></script>
|
||||||
|
|
||||||
|
{import.meta.env.PROD && ScssProd && (
|
||||||
<Stylesheet direction={direction} layout={layout} />
|
<Stylesheet direction={direction} layout={layout} />
|
||||||
<Scss />
|
<ScssProd.default />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!import.meta.env.PROD && Scss && (
|
||||||
|
<Scss.default />
|
||||||
|
)}
|
||||||
|
|
||||||
<Favicons />
|
<Favicons />
|
||||||
<Social description={description} layout={layout} thumbnail={thumbnail} title={title} />
|
<Social description={description} layout={layout} thumbnail={thumbnail} title={title} />
|
||||||
<Analytics />
|
<Analytics />
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
<style is:global lang="scss">
|
<style is:global lang="scss">
|
||||||
|
@import '../../../../scss/bootstrap.scss';
|
||||||
@import '../../scss/docs';
|
@import '../../scss/docs';
|
||||||
@import '../../scss/docs_search';
|
@import '../../scss/docs_search';
|
||||||
</style>
|
</style>
|
||||||
|
7
site/src/components/head/ScssProd.astro
Normal file
7
site/src/components/head/ScssProd.astro
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
|
<style is:global lang="scss">
|
||||||
|
@import '../../scss/docs';
|
||||||
|
@import '../../scss/docs_search';
|
||||||
|
</style>
|
@ -40,7 +40,7 @@ try {
|
|||||||
|
|
||||||
content = matches[1]
|
content = matches[1]
|
||||||
|
|
||||||
// Fix the identation by removing extra spaces at the beginning of each line
|
// Fix the indentation by removing extra spaces at the beginning of each line
|
||||||
const lines = content.split('\n')
|
const lines = content.split('\n')
|
||||||
const spaceCounts = lines.filter((line) => line.trim().length > 0).map((line) => line.match(/^ */)[0].length)
|
const spaceCounts = lines.filter((line) => line.trim().length > 0).map((line) => line.match(/^ */)[0].length)
|
||||||
const minSpaces = spaceCounts.length ? Math.min(...spaceCounts) : 0
|
const minSpaces = spaceCounts.length ? Math.min(...spaceCounts) : 0
|
||||||
|
@ -42,7 +42,7 @@ try {
|
|||||||
|
|
||||||
content = matches[1].replaceAll(' !default', '')
|
content = matches[1].replaceAll(' !default', '')
|
||||||
|
|
||||||
// Fix the identation by removing extra spaces at the beginning of each line
|
// Fix the indentation by removing extra spaces at the beginning of each line
|
||||||
const lines = content.split('\n')
|
const lines = content.split('\n')
|
||||||
const spaceCounts = lines.filter((line) => line.trim().length > 0).map((line) => line.match(/^ */)[0].length)
|
const spaceCounts = lines.filter((line) => line.trim().length > 0).map((line) => line.match(/^ */)[0].length)
|
||||||
const minSpaces = spaceCounts.length ? Math.min(...spaceCounts) : 0
|
const minSpaces = spaceCounts.length ? Math.min(...spaceCounts) : 0
|
||||||
|
@ -120,7 +120,7 @@ function bootstrap_auto_import() {
|
|||||||
const autoImportedComponentDefinition = `/**
|
const autoImportedComponentDefinition = `/**
|
||||||
* DO NOT EDIT THIS FILE MANUALLY.
|
* DO NOT EDIT THIS FILE MANUALLY.
|
||||||
*
|
*
|
||||||
* This file is automatically generated by the Boostrap Astro Integration.
|
* This file is automatically generated by the Bootstrap Astro Integration.
|
||||||
* It contains the type definitions for the components that are auto imported in all pages.
|
* It contains the type definitions for the components that are auto imported in all pages.
|
||||||
* @see site/src/libs/astro.ts
|
* @see site/src/libs/astro.ts
|
||||||
*/
|
*/
|
||||||
|
@ -25,8 +25,8 @@ export function getVersionedDocsPath(docsPath: string): string {
|
|||||||
// This is useful to catch typos in docs paths.
|
// This is useful to catch typos in docs paths.
|
||||||
// Note: this function is only called during a production build.
|
// Note: this function is only called during a production build.
|
||||||
// Note: this could at some point be refactored to use Astro list of generated `routes` accessible in the
|
// Note: this could at some point be refactored to use Astro list of generated `routes` accessible in the
|
||||||
// `astro:build:done` integration hook. Altho as of 03/14/2023, this is not possible due to the route's data only
|
// `astro:build:done` integration hook. Although as of 03/14/2023, this is not possible due to the route's data only
|
||||||
// containing informations regarding the last page generated page for dynamic routes.
|
// containing information regarding the last page generated page for dynamic routes.
|
||||||
// @see https://github.com/withastro/astro/issues/5802
|
// @see https://github.com/withastro/astro/issues/5802
|
||||||
export function validateVersionedDocsPaths(distUrl: URL) {
|
export function validateVersionedDocsPaths(distUrl: URL) {
|
||||||
const { docs_version } = getConfig()
|
const { docs_version } = getConfig()
|
||||||
|
@ -215,13 +215,13 @@ export interface PlaceholderOptions {
|
|||||||
*/
|
*/
|
||||||
markup: 'img' | 'svg'
|
markup: 'img' | 'svg'
|
||||||
/**
|
/**
|
||||||
* The text to show in the image. You can explicitely pass the `false` boolean value (and not the string "false") to
|
* The text to show in the image. You can explicitly pass the `false` boolean value (and not the string "false") to
|
||||||
* hide the text.
|
* hide the text.
|
||||||
* @default "${width}x{$height)"
|
* @default "${width}x{$height)"
|
||||||
*/
|
*/
|
||||||
text: string | false
|
text: string | false
|
||||||
/**
|
/**
|
||||||
* Used in the SVG `title` tag. You can explicitely pass the `false` boolean value (and not the string "false") to
|
* Used in the SVG `title` tag. You can explicitly pass the `false` boolean value (and not the string "false") to
|
||||||
* hide the title.
|
* hide the title.
|
||||||
* @default "Placeholder"
|
* @default "Placeholder"
|
||||||
*/
|
*/
|
||||||
|
@ -56,7 +56,7 @@ export const remarkBsConfig: Plugin<[], Root> = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A remark plugin to add versionned docs links in markdown (or MDX) files.
|
// A remark plugin to add versioned docs links in markdown (or MDX) files.
|
||||||
// For example, [[docsref:/foo]] will be replaced with the `/docs/${docs_version}/foo` value with the `docs_version`
|
// For example, [[docsref:/foo]] will be replaced with the `/docs/${docs_version}/foo` value with the `docs_version`
|
||||||
// value being read from the `config.yml` file.
|
// value being read from the `config.yml` file.
|
||||||
// Note: this also works in frontmatter.
|
// Note: this also works in frontmatter.
|
||||||
|
2
site/src/types/auto-import.d.ts
vendored
2
site/src/types/auto-import.d.ts
vendored
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* DO NOT EDIT THIS FILE MANUALLY.
|
* DO NOT EDIT THIS FILE MANUALLY.
|
||||||
*
|
*
|
||||||
* This file is automatically generated by the Boostrap Astro Integration.
|
* This file is automatically generated by the Bootstrap Astro Integration.
|
||||||
* It contains the type definitions for the components that are auto imported in all pages.
|
* It contains the type definitions for the components that are auto imported in all pages.
|
||||||
* @see site/src/libs/astro.ts
|
* @see site/src/libs/astro.ts
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user