Compare commits

..

13 Commits

Author SHA1 Message Date
Mark Otto 1f28c7684f test 2025-04-23 14:43:31 -07:00
Julien Déramond 9f4d383046 Remove files configuration from .cspell.json (#41400) 2025-04-22 09:16:54 +02:00
Jason Dent a4b37547a3 Spell check .md and .mdx files (#41398)
Co-authored-by: Julien Déramond <juderamond@gmail.com>
2025-04-22 08:54:19 +02:00
Julien Déramond bd09d21ed6 Fix typos and code indentation in Forms > Checks and radios (#41399) 2025-04-22 08:44:44 +02:00
Mark Otto 24305e7b18 Attempt to return focus explicitly to dropdown trigger (#41365)
Co-authored-by: Mark Otto <mdo@heypierre.app>
2025-04-21 21:20:09 -07:00
Tommaso Allegretti 1d441c7c7f Docs: add Usage section with JavaScript guide for Accordion component (#40768)
Co-authored-by: Julien Déramond <juderamond@gmail.com>
Co-authored-by: Tommaso Allegretti <tommasoallegretti@users.noreply.github.com>
2025-04-21 21:04:20 -07:00
Mark Otto 1a6175a1c6 Alternate for #41142, disabled list group items (#41397) 2025-04-21 21:03:10 -07:00
Mohamad Salman 5c5f2913df Add private comment to BaseComponent Class (#41254) 2025-04-21 20:33:04 -07:00
Mark Otto dd4e14499f Add switch attribute to docs for switch checkbox (#41396)
* Add switch attribute to docs for switch checkbox

* tweak

* AI says this is the way

* fix
2025-04-21 20:32:40 -07:00
Julien Déramond ed36faae9d Bump image-size from 1.0.2 to 2.0.2 (#41384) 2025-04-15 21:18:13 +02:00
Julien Déramond d01e66f5f7 Update devDependencies (#41383) 2025-04-15 21:09:29 +02:00
XhmikosR 2b55a457ce Update dependabot.yml 2025-04-15 20:56:27 +03:00
Julien Déramond a8ab19955b Docs: migration from Hugo to Astro (#41251)
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>
Co-authored-by: Mark Otto <markdotto@gmail.com>
2025-04-15 18:37:47 +02:00
20 changed files with 434 additions and 753 deletions
-3
View File
@@ -120,9 +120,6 @@
"zindex"
],
"language": "en-US",
"files": [
"**/*.md"
],
"ignorePaths": [
".cspell.json",
"dist/",
-2
View File
@@ -9,8 +9,6 @@ updates:
timezone: Europe/Athens
- package-ecosystem: npm
directory: "/"
reviewers:
- XhmikosR
labels:
- dependencies
- v5
+1 -1
View File
@@ -31,6 +31,6 @@ jobs:
uses: streetsidesoftware/cspell-action@v6
with:
config: ".cspell.json"
files: "**/*.md"
files: "**/*.{md,mdx}"
inline: error
incremental_files_only: false
-4
View File
@@ -44,7 +44,3 @@ Thumbs.db
/site/node_modules
/site/.astro
/site/public
# TODO(Astro migration): temporary files and directories during the migration
resources/
.hugo_build.lock
+3 -1
View File
@@ -35,7 +35,9 @@ execFile('java', ['-version'], (error, stdout, stderr) => {
'Attribute “is:raw” is not serializable as XML 1.0.',
'Attribute “is:raw” not allowed on element “code” at this point.',
// Astro's expecting trailing slashes on HTML tags such as <br />
'Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.'
'Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.',
// Allow `switch` attribute.
'Attribute “switch” not allowed on element “input” at this point.'
].join('|')
const args = [
View File
+1
View File
@@ -45,6 +45,7 @@ class BaseComponent extends Config {
}
}
// Private
_queueCallback(callback, element, isAnimated = true) {
executeAfterTransition(callback, element, isAnimated)
}
+3
View File
@@ -207,6 +207,9 @@ class Dropdown extends BaseComponent {
this._element.setAttribute('aria-expanded', 'false')
Manipulator.removeDataAttribute(this._menu, 'popper')
EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
// Explicitly return focus to the trigger element
this._element.focus()
}
_getConfig(config) {
+304 -523
View File
File diff suppressed because it is too large Load Diff
+11 -11
View File
@@ -110,7 +110,7 @@
"devDependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/markdown-remark": "^6.3.1",
"@astrojs/mdx": "^4.2.3",
"@astrojs/mdx": "^4.2.4",
"@astrojs/prism": "^3.2.0",
"@astrojs/sitemap": "^3.3.0",
"@babel/cli": "^7.27.0",
@@ -123,14 +123,14 @@
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-replace": "^6.0.2",
"@stackblitz/sdk": "^1.11.0",
"@types/google.analytics": "^0.0.42",
"@types/google.analytics": "^0.0.46",
"@types/js-yaml": "^4.0.5",
"@types/mime": "^3.0.1",
"@types/prismjs": "^1.26.0",
"astro": "^5.6.1",
"astro": "^5.7.0",
"astro-auto-import": "^0.4.4",
"autoprefixer": "^10.4.21",
"bundlewatch": "^0.4.0",
"bundlewatch": "^0.4.1",
"clean-css-cli": "^5.6.3",
"clipboard": "^2.0.11",
"cross-env": "^7.0.3",
@@ -144,8 +144,8 @@
"github-slugger": "^2.0.0",
"globby": "^14.1.0",
"hammer-simulator": "0.0.1",
"htmlparser2": "^8.0.1",
"image-size": "^1.0.2",
"htmlparser2": "^10.0.0",
"image-size": "^2.0.2",
"ip": "^2.0.1",
"jasmine": "^5.6.0",
"jquery": "^3.7.1",
@@ -160,14 +160,14 @@
"karma-jasmine-html-reporter": "^2.1.0",
"karma-rollup-preprocessor": "7.0.7",
"lockfile-lint": "^4.14.0",
"mime": "^3.0.0",
"mime": "^4.0.7",
"nodemon": "^3.1.9",
"npm-run-all2": "^7.0.2",
"postcss": "^8.5.3",
"postcss-cli": "^11.0.1",
"prettier": "^2.8.4",
"prettier-plugin-astro": "^0.8.0",
"rehype-autolink-headings": "^6.1.1",
"prettier": "^3.5.3",
"prettier-plugin-astro": "^0.14.1",
"rehype-autolink-headings": "^7.1.0",
"remark": "^15.0.1",
"remark-html": "^16.0.1",
"rollup": "^4.38.0",
@@ -179,7 +179,7 @@
"stylelint": "^16.17.0",
"stylelint-config-twbs-bootstrap": "^16.0.0",
"terser": "^5.39.0",
"unist-util-visit": "^4.1.2",
"unist-util-visit": "^5.0.0",
"vnu-jar": "24.10.17",
"zod": "^3.20.6"
},
+4 -4
View File
@@ -11,10 +11,10 @@ const site = isDev
? // In development mode, use the local dev server.
'http://localhost:4321'
: process.env.DEPLOY_PRIME_URL !== undefined
? // If deploying on Netlify, use the `DEPLOY_PRIME_URL` environment variable.
process.env.DEPLOY_PRIME_URL
: // Otherwise, use the `baseURL` value defined in the `config.yml` file.
getConfig().baseURL
? // If deploying on Netlify, use the `DEPLOY_PRIME_URL` environment variable.
process.env.DEPLOY_PRIME_URL
: // Otherwise, use the `baseURL` value defined in the `config.yml` file.
getConfig().baseURL
// https://astro.build/config
export default defineConfig({
-1
View File
@@ -6,7 +6,6 @@
icon_color: indigo
pages:
- title: Introduction
- title: Install
- title: Download
- title: Contents
- title: Browsers & devices
-61
View File
@@ -1,61 +0,0 @@
---
interface Tab {
id: string;
title: string;
active?: boolean;
content: string;
}
interface Props {
tabs: Tab[];
id?: string;
}
const { tabs, id = "tabNav" } = Astro.props;
---
<ul class="nav nav-tabs" id={id} role="tablist">
{tabs.map((tab, index) => (
<li class="nav-item" role="presentation">
<button
class={`nav-link ${tab.active ? 'active' : ''}`}
id={`${tab.id}-tab`}
data-bs-toggle="tab"
data-bs-target={`#${tab.id}`}
type="button"
role="tab"
aria-controls={tab.id}
aria-selected={tab.active ? 'true' : 'false'}
>
{tab.title}
</button>
</li>
))}
</ul>
<div class="tab-content">
{tabs.map((tab) => (
<div
class={`tab-pane ${tab.active ? 'active' : ''}`}
id={tab.id}
role="tabpanel"
aria-labelledby={`${tab.id}-tab`}
tabindex="0"
>
<Fragment set:html={tab.content} />
</div>
))}
</div>
<script>
// Initialize Bootstrap tabs if they haven't been already
document.addEventListener('DOMContentLoaded', () => {
// Check if Bootstrap is available
if (typeof bootstrap !== 'undefined') {
const tabElements = document.querySelectorAll('[data-bs-toggle="tab"]');
tabElements.forEach(el => {
new bootstrap.Tab(el);
});
}
});
</script>
+1 -1
View File
@@ -14,7 +14,7 @@ interface Props {
const { description, layout, thumbnail, title } = Astro.props
const socialImageUrl = new URL(getVersionedDocsPath(`assets/${thumbnail}`), Astro.site)
const socialImageSize = getStaticImageSize(`/docs/[version]/assets/${thumbnail}`)
const socialImageSize = await getStaticImageSize(`/docs/[version]/assets/${thumbnail}`)
---
<meta name="twitter:card" content="summary_large_image" />
@@ -157,3 +157,84 @@ As part of Bootstraps evolving CSS variables approach, accordions now use loc
### Sass variables
<ScssDocs name="accordion-variables" file="scss/_variables.scss" />
## Usage
The collapse plugin utilizes a few classes to handle the heavy lifting:
- `.collapse` hides the content
- `.collapse.show` shows the content
- `.collapsing` is added when the transition starts, and removed when it finishes
These classes can be found in `_transitions.scss`.
### Via data attributes
Just add `data-bs-toggle="collapse"` and a `data-bs-target` to the element to automatically assign control of one or more collapsible elements. The `data-bs-target` attribute accepts a CSS selector to apply the collapse to. Be sure to add the class `collapse` to the collapsible element. If youd like it to default open, add the additional class `show`.
To add accordion group management to a collapsible area, add the data attribute `data-bs-parent="#selector"`.
### Via JavaScript
Enable manually with:
```js
const accordionCollapseElementList = document.querySelectorAll('#myAccordion.collapse')
const accordionCollapseList = [...accordionCollapseElementList].map(accordionCollapseEl => new bootstrap.Collapse(accordionCollapseEl))
```
### Options
<JsDataAttributes />
<BsTable>
| Name | Type | Default | Description |
| --- | --- | --- | --- |
`parent` | selector, DOM element | `null` | If parent is provided, then all collapsible elements under the specified parent will be closed when this collapsible item is shown. (similar to traditional accordion behavior - this is dependent on the `card` class). The attribute has to be set on the target collapsible area. |
`toggle` | boolean | `true` | Toggles the collapsible element on invocation. |
</BsTable>
### Methods
<Callout name="danger-async-methods" type="danger" />
Activates your content as a collapsible element. Accepts an optional options `object`.
You can create a collapse instance with the constructor, for example:
```js
const bsCollapse = new bootstrap.Collapse('#myCollapse', {
toggle: false
})
```
<BsTable>
| Method | Description |
| --- | --- |
| `dispose` | Destroys an elements collapse. (Removes stored data on the DOM element) |
| `getInstance` | Static method which allows you to get the collapse instance associated to a DOM element, you can use it like this: `bootstrap.Collapse.getInstance(element)`. |
| `getOrCreateInstance` | Static method which returns a collapse instance associated to a DOM element or create a new one in case it wasnt initialized. You can use it like this: `bootstrap.Collapse.getOrCreateInstance(element)`. |
| `hide` | Hides a collapsible element. **Returns to the caller before the collapsible element has actually been hidden** (e.g., before the `hidden.bs.collapse` event occurs). |
| `show` | Shows a collapsible element. **Returns to the caller before the collapsible element has actually been shown** (e.g., before the `shown.bs.collapse` event occurs). |
| `toggle` | Toggles a collapsible element to shown or hidden. **Returns to the caller before the collapsible element has actually been shown or hidden** (i.e. before the `shown.bs.collapse` or `hidden.bs.collapse` event occurs). |
</BsTable>
### Events
Bootstraps collapse class exposes a few events for hooking into collapse functionality.
<BsTable>
| Event type | Description |
| --- | --- |
| `hide.bs.collapse` | This event is fired immediately when the `hide` method has been called. |
| `hidden.bs.collapse` | This event is fired when a collapse element has been hidden from the user (will wait for CSS transitions to complete). |
| `show.bs.collapse` | This event fires immediately when the `show` instance method is called. |
| `shown.bs.collapse` | This event is fired when a collapse element has been made visible to the user (will wait for CSS transitions to complete). |
</BsTable>
```js
const myCollapsible = document.getElementById('myCollapsible')
myCollapsible.addEventListener('hidden.bs.collapse', event => {
// do something...
})
```
@@ -30,22 +30,12 @@ Add `.active` to a `.list-group-item` to indicate the current active selection.
<li class="list-group-item">And a fifth one</li>
</ul>`} />
## Disabled items
Add `.disabled` to a `.list-group-item` to make it _appear_ disabled. Note that some elements with `.disabled` will also require custom JavaScript to fully disable their click events (e.g., links).
<Example code={`<ul class="list-group">
<li class="list-group-item disabled" aria-disabled="true">A disabled item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">And a fifth one</li>
</ul>`} />
## Links and buttons
Use `<a>`s or `<button>`s to create _actionable_ list group items with hover, disabled, and active states by adding `.list-group-item-action`. We separate these pseudo-classes to ensure list groups made of non-interactive elements (like `<li>`s or `<div>`s) dont provide a click or tap affordance.
Make `.list-group-item-action` instances _appear_ disabled by adding `.disabled`, and `aria-disabled="true"` to inform assistive technologies that the element is disabled. You may require additional JavaScript to fully disable links and buttons.
Be sure to **not use the standard `.btn` classes here**.
<Example code={`<div class="list-group">
@@ -55,7 +45,7 @@ Be sure to **not use the standard `.btn` classes here**.
<a href="#" class="list-group-item list-group-item-action">A second link item</a>
<a href="#" class="list-group-item list-group-item-action">A third link item</a>
<a href="#" class="list-group-item list-group-item-action">A fourth link item</a>
<a class="list-group-item list-group-item-action disabled" aria-disabled="true">A disabled link item</a>
<a href="#" class="list-group-item list-group-item-action disabled" aria-disabled="true">A disabled link item</a>
</div>`} />
With `<button>`s, you can also make use of the `disabled` attribute instead of the `.disabled` class. Sadly, `<a>`s dont support the disabled attribute.
+14 -1
View File
@@ -115,6 +115,19 @@ A switch has the markup of a custom checkbox but uses the `.form-switch` class t
<label class="form-check-label" for="switchCheckCheckedDisabled">Disabled checked switch checkbox input</label>
</div>`} />
### Native switches
Progressively enhance your switches for mobile Safari (iOS 17.4+) by adding a `switch` attribute to your input to enable haptic feedback when toggling switches, just like native iOS switches. There are no style changes attached to using this attribute in Bootstrap as all our switches use custom styles.
<Example code={`<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" value="" id="checkNativeSwitch" switch>
<label class="form-check-label" for="checkNativeSwitch">
Native switch haptics
</label>
</div>`} />
Be sure to read more about [the switch attribute on the WebKit blog](https://webkit.org/blog/15054/an-html-switch-control/). Safari 17.4+ on macOS and iOS both have native-style switches in HTML while other browsers simply fall back to the standard checkbox appearance. Applying the attribute to a non-Bootstrap checkbox in more recent versions of Safari will render a native switch.
## Default (stacked)
By default, any number of checkboxes and radios that are immediate sibling will be vertically stacked and appropriately spaced with `.form-check`.
@@ -240,7 +253,7 @@ Create button-like checkboxes and radio buttons by using `.btn` styles rather th
<label class="btn" for="btn-check-6">Disabled</label>`} />
<Callout>
Visually, these checkbox toggle buttons are identical to the [button plugin toggle buttons]([[docsref:/components/buttons#button-plugin]]). However, they are conveyed differently by assistive technologies: the checkbox toggles will be announced by screen readers as “checked/“not checked (since, despite their appearance, they are fundamentally still checkboxes), whereas the button plugin toggle buttons will be announced as “button/“button pressed. The choice between these two approaches will depend on the type of toggle you are creating, and whether or not the toggle will make sense to users when announced as a checkbox or as an actual button.
Visually, these checkbox toggle buttons are identical to the [button plugin toggle buttons]([[docsref:/components/buttons#button-plugin]]). However, they are conveyed differently by assistive technologies: the checkbox toggles will be announced by screen readers as “checked/“not checked (since, despite their appearance, they are fundamentally still checkboxes), whereas the button plugin toggle buttons will be announced as “button/“button pressed. The choice between these two approaches will depend on the type of toggle you are creating, and whether or not the toggle will make sense to users when announced as a checkbox or as an actual button.
</Callout>
### Radio toggle buttons
@@ -1,122 +0,0 @@
---
title: Install Bootstrap
description: …
toc: true
---
import Tab from '../../../components/Tab.astro';
<Tab
tabs={[
{
id: "home",
title: "Default first",
active: true,
content: "default tab"
},
{
id: "profile",
title: "Second",
content: "second tab"
},
{
id: "messages",
title: "Third",
content: "third tab"
}
]}
id="myTab"
/>
```
// Modern fluid sizing system using clamp()
// Provides a simpler alternative to RFS while maintaining similar functionality
// Convert a px value to rem
@function px-to-rem($px) {
@return math.div($px, 16) * 1rem;
}
// Strip unit from a value
@function strip-unit($value) {
@return math.div($value, ($value * 0 + 1));
}
// Core fluid sizing mixin
@mixin fluid-size($property, $min-size, $max-size, $min-vw: 320px, $max-vw: 1200px) {
$min-size-rem: if(unit($min-size) == px, px-to-rem($min-size), $min-size);
$max-size-rem: if(unit($max-size) == px, px-to-rem($max-size), $max-size);
$min-vw-rem: if(unit($min-vw) == px, px-to-rem($min-vw), $min-vw);
$max-vw-rem: if(unit($max-vw) == px, px-to-rem($max-vw), $max-vw);
#{$property}: clamp(
#{$min-size-rem},
#{$min-size-rem} + #{strip-unit($max-size-rem - $min-size-rem)} *
((100vw - #{$min-vw-rem}) / #{strip-unit($max-vw-rem - $min-vw-rem)}),
#{$max-size-rem}
);
}
// Fluid font-size mixin - direct replacement for rfs font-size
@mixin fluid-font-size($size) {
$min-size: if($size < 1.25rem, $size, 1.25rem);
$max-size: $size;
@include fluid-size(font-size, $min-size, $max-size);
}
// Fluid padding mixins
@mixin fluid-padding($size) {
@include fluid-size(padding, $size * 0.5, $size);
}
@mixin fluid-padding-top($size) {
@include fluid-size(padding-top, $size * 0.5, $size);
}
@mixin fluid-padding-right($size) {
@include fluid-size(padding-right, $size * 0.5, $size);
}
@mixin fluid-padding-bottom($size) {
@include fluid-size(padding-bottom, $size * 0.5, $size);
}
@mixin fluid-padding-left($size) {
@include fluid-size(padding-left, $size * 0.5, $size);
}
// Fluid margin mixins
@mixin fluid-margin($size) {
@include fluid-size(margin, $size * 0.5, $size);
}
@mixin fluid-margin-top($size) {
@include fluid-size(margin-top, $size * 0.5, $size);
}
@mixin fluid-margin-right($size) {
@include fluid-size(margin-right, $size * 0.5, $size);
}
@mixin fluid-margin-bottom($size) {
@include fluid-size(margin-bottom, $size * 0.5, $size);
}
@mixin fluid-margin-left($size) {
@include fluid-size(margin-left, $size * 0.5, $size);
}
// Legacy compatibility mixins - these provide a bridge from RFS to the new system
@mixin font-size($size) {
@include fluid-font-size($size);
}
@mixin padding($size) {
@include fluid-padding($size);
}
@mixin margin($size) {
@include fluid-margin($size);
}
```
+6 -3
View File
@@ -1,11 +1,14 @@
import path from 'node:path'
import { promises as fs } from 'node:fs'
import sizeOf from 'image-size'
import { getDocsStaticFsPath } from './path'
export function getStaticImageSize(imagePath: string) {
const size = sizeOf(path.join(getDocsStaticFsPath(), imagePath))
export async function getStaticImageSize(imagePath: string) {
const fullPath = path.join(getDocsStaticFsPath(), imagePath)
const buffer = await fs.readFile(fullPath)
const size = await sizeOf(buffer)
if (!size.height || !size.width) {
if (!size?.height || !size?.width) {
throw new Error(`Failed to get size of static image at '${imagePath}'.`)
}
+2 -2
View File
@@ -147,8 +147,8 @@ function replaceInFrontmatter(record: Record<string, unknown>, replacer: (value:
return typeof arrayValue === 'string'
? replacer(arrayValue)
: typeof arrayValue === 'object'
? replaceInFrontmatter(arrayValue, replacer)
: arrayValue
? replaceInFrontmatter(arrayValue, replacer)
: arrayValue
})
}
}