diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 014da501..21939fe5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,12 +19,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [22.x, 24.x]
+ node-version: [22.x, 24.x, 26.x]
steps:
- name: Checkout repository
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Set up Node.js
- uses: actions/setup-node@v6
+ uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
@@ -42,11 +42,11 @@ jobs:
name: coverage-report-${{ matrix.node-version }}
path: coverage
- name: Upload coverage report to Coveralls
- #v2.3.7
- uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e
+ uses: coverallsapp/github-action@8d6379e14d29928660c4ba802d8e85393440b329
with:
flag-name: coverage-report-${{ matrix.node-version }}
parallel: true
+ continue-on-error: true
coverage-finished:
name: Publish coverage report to Coveralls
@@ -55,11 +55,50 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
- #v2.3.7
- uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e
+ id: coveralls
+ uses: coverallsapp/github-action@8d6379e14d29928660c4ba802d8e85393440b329
with:
parallel-finished: true
- carryforward: "coverage-report-22.x,coverage-report-24.x"
+ carryforward: "coverage-report-22.x,coverage-report-24.x,coverage-report-26.x"
+ continue-on-error: true
+
+ - name: Check Coveralls status
+ id: check-status
+ if: always()
+ run: |
+ if [ "${{ steps.coveralls.outcome }}" == "success" ]; then
+ echo "✅ Coveralls report submitted successfully"
+ echo "status=success" >> $GITHUB_OUTPUT
+ elif [ "${{ steps.coveralls.outcome }}" == "failure" ]; then
+ echo "⚠️ Coveralls service is temporarily unavailable"
+ echo "status=neutral" >> $GITHUB_OUTPUT
+ else
+ echo "❓ Coveralls status unknown: ${{ steps.coveralls.outcome }}"
+ echo "status=neutral" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Set neutral status (if needed)
+ if: steps.check-status.outputs.status == 'neutral'
+ uses: actions/github-script@v9
+ with:
+ script: |
+ const { context } = require('@actions/github');
+ const owner = context.repo.owner;
+ const repo = context.repo.repo;
+ const sha = context.sha;
+
+ await github.rest.checks.create({
+ owner,
+ repo,
+ name: 'Coveralls / Coverage Report',
+ head_sha: sha,
+ status: 'completed',
+ conclusion: 'neutral',
+ output: {
+ title: 'Coveralls service temporarily unavailable',
+ summary: '⚠️ Coveralls is currently experiencing issues. The coverage report will be submitted when the service is available again.\n\nThis check is marked as neutral and does not block the PR.'
+ }
+ });
cypress:
name: Run e2e tests with Cypress
@@ -70,14 +109,13 @@ jobs:
options: --user 1001
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Install dependencies
run: npm install
- name: Build project
run: npm run build
- name: Cypress run
- #v6.10.8
- uses: cypress-io/github-action@948d67d3074f1bbb6379c8bdbb04e95d2f8e593f
+ uses: cypress-io/github-action@c541a95ea92d9239347a2355f2e895cd4b3f8060
with:
browser: chrome
@@ -91,7 +129,7 @@ jobs:
security-events: write
steps:
- name: Checkout repository
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
@@ -107,18 +145,44 @@ jobs:
needs: build-and-test
steps:
- name: Checkout repository
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
with:
fetch-depth: 0
+ - name: Get changed files
+ id: changed-files
+ uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96
+ with:
+ files: |
+ **
+ files_ignore: |
+ package.json
+ .npmrc
+ **/*.md
+ .github/**
+ .gitignore
+
+ - name: Check if code changes exist
+ id: check-changes
+ run: |
+ if [ "${{ steps.changed-files.outputs.any_changed }}" == "true" ]; then
+ echo "has_code_changes=true" >> $GITHUB_OUTPUT
+ echo "📝 Code changes detected in:"
+ echo "${{ steps.changed-files.outputs.all_changed_files }}"
+ else
+ echo "has_code_changes=false" >> $GITHUB_OUTPUT
+ echo "📦 Only dependency, documentation or CI/CD files changed"
+ fi
+
- name: Download coverage artifact
+ if: steps.check-changes.outputs.has_code_changes == 'true'
uses: actions/download-artifact@v8
with:
- name: coverage-report-22.x
+ name: coverage-report-26.x
path: coverage
- name: SonarQube Scan
- # v7.0.0
- uses: SonarSource/sonarqube-scan-action@59db25f34e16620e48ab4bb9e4a5dce155cb5432
+ if: steps.check-changes.outputs.has_code_changes == 'true'
+ uses: SonarSource/sonarqube-scan-action@d209202bc7d53ff1cc128f7f907dac145c9d6ae9
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml
index 528d4266..a9d5537a 100644
--- a/.github/workflows/deploy-docs.yml
+++ b/.github/workflows/deploy-docs.yml
@@ -1,10 +1,8 @@
name: Deploy documentation
on:
- push:
- branches: [ "v5" ]
- pull_request:
- branches: [ "v5" ]
+ release:
+ types: [published]
workflow_dispatch:
permissions:
@@ -24,11 +22,11 @@ jobs:
working-directory: docs
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Use Node.js
- uses: actions/setup-node@v6
+ uses: actions/setup-node@v7
with:
- node-version: 24.x
+ node-version: 26.x
- name: Install dependencies
run: npm install
- name: Build
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..1f16cffb
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,44 @@
+name: Publish Package to npmJS
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ id-token: write
+ steps:
+ - uses: actions/checkout@v7
+
+ - uses: actions/setup-node@v7
+ with:
+ node-version: '26.x'
+
+ - name: Install dependencies
+ run: npm install
+
+ - name: Determine npm tag
+ id: npm-tag
+ run: |
+ RELEASE_NAME="${{ github.event.release.name }}"
+ RELEASE_TAG="${{ github.event.release.tag_name }}"
+
+ echo "📦 Release name: $RELEASE_NAME"
+ echo "🏷️ Release tag: $RELEASE_TAG"
+
+ if [ "${{ github.event.release.prerelease }}" == "true" ]; then
+ echo "🔬 Prerelease detected - using 'next' tag"
+ echo "tag=next" >> $GITHUB_OUTPUT
+ else
+ echo "🚀 Full release detected - using 'latest' tag"
+ echo "tag=latest" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Stage publish to npm
+ run: |
+ npm stage publish --provenance --access public --tag ${{ steps.npm-tag.outputs.tag }}
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
\ No newline at end of file
diff --git a/README.md b/README.md
index bb7d17b3..f538b0f1 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,6 @@ See EOL for each version in [Security Policy Page](https://github.com/palcarazm/
-
- [Installation](#installation)
- [CDN](#cdn)
- [ECMAS Interface](#ecmas-interface)
@@ -54,6 +53,7 @@ See EOL for each version in [Security Policy Page](https://github.com/palcarazm/
+
---
# Installation
@@ -66,18 +66,18 @@ See EOL for each version in [Security Policy Page](https://github.com/palcarazm/
```html
-
+
```
### jQuery Interface
```html
-
+
```
## Download
@@ -89,13 +89,13 @@ See EOL for each version in [Security Policy Page](https://github.com/palcarazm/
[](https://www.npmjs.com/package/bootstrap5-toggle)
```ksh
-npm install bootstrap5-toggle@5.4.1
+npm install bootstrap5-toggle@5.5.0
```
## Yarn
```ksh
-yarn add bootstrap5-toggle@5.4.1
+yarn add bootstrap5-toggle@5.5.0
```
# Usage
diff --git a/cypress.config.cjs b/cypress.config.cjs
index 460e0b48..6dd145bf 100644
--- a/cypress.config.cjs
+++ b/cypress.config.cjs
@@ -1,7 +1,6 @@
const { defineConfig } = require("cypress");
module.exports = defineConfig({
- allowCypressEnv: false,
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
diff --git a/cypress/e2e/monitoring.spec.cy.js b/cypress/e2e/monitoring.spec.cy.js
new file mode 100644
index 00000000..174dad3c
--- /dev/null
+++ b/cypress/e2e/monitoring.spec.cy.js
@@ -0,0 +1,124 @@
+/// role="switch" attribute, allowing screen readers to identify it as a toggleable control.`,
- },
- {
- title: "State Representation",
- description: `The aria-checked attribute dynamically reflects the toggle's state (on/off), providing real-time feedback to assistive technologies.`,
- },
- {
- title: "Labeling",
- description: `Toggles can be associated with descriptive labels using the aria-labelledby or aria-label attributes, enhancing clarity for screen reader users.`,
- },
+ static #features = [
+ {
+ title: "Semantic Role Implementation",
+ description: "Each toggle switch is assigned the role=\"switch\" attribute, allowing screen readers to identify it as a toggleable control.",
+ },
+ {
+ title: "State Representation",
+ description: "The aria-checked attribute dynamically reflects the toggle's state (on/off), providing real-time feedback to assistive technologies.",
+ },
+ {
+ title: "Labeling",
+ description: "Toggles can be associated with descriptive labels using the aria-labelledby or aria-label attributes, enhancing clarity for screen reader users.",
+ },
- {
- title: "Keyboard Navigation",
- description: `The toggle supports keyboard navigation with TAB and ENTER keys, ensuring full accessibility for users who rely on keyboard input.`,
- },
- {
- title: "Indeterminate State Accessibility",
- description: `When a toggle is in an indeterminate state, it uses the aria-checked="mixed" attribute to inform assistive technologies of its unique status.`,
- },
- {
- title: "Focus Management",
- description: `The toggle is fully focusable and provides visual focus indicators, aiding users in tracking their navigation through the interface.`,
- },
- ];
+ {
+ title: "Keyboard Navigation",
+ description: "The toggle supports keyboard navigation with TAB and ENTER keys, ensuring full accessibility for users who rely on keyboard input.",
+ },
+ {
+ title: "Indeterminate State Accessibility",
+ description: "When a toggle is in an indeterminate state, it uses the aria-checked=\"mixed\" attribute to inform assistive technologies of its unique status.",
+ },
+ {
+ title: "Focus Management",
+ description: "The toggle is fully focusable and provides visual focus indicators, aiding users in tracking their navigation through the interface.",
+ },
+ ];
- static #featuresCards() {
- const fragment = document.createDocumentFragment();
+ static #featuresCards() {
+ const fragment = document.createDocumentFragment();
- const description = document.createElement("p");
- description.innerHTML = `Bootstrap Toggle is built with accessibility in mind. The implementation ensures seamless compatibility with screen readers, keyboard navigation, and other assistive technologies.`;
- fragment.appendChild(description);
+ const description = document.createElement("p");
+ description.innerHTML = "Bootstrap Toggle is built with accessibility in mind. The implementation ensures seamless compatibility with screen readers, keyboard navigation, and other assistive technologies.";
+ fragment.appendChild(description);
- const container = document.createElement("div");
- container.classList.add(
- "row",
- "row-cols-1",
- "row-cols-md-2",
- "row-cols-xl-3",
- "g-4",
- );
- Accessibility.#features.forEach((feature) => {
- const col = document.createElement("div");
- col.classList.add("col");
+ const container = document.createElement("div");
+ container.classList.add(
+ "row",
+ "row-cols-1",
+ "row-cols-md-2",
+ "row-cols-xl-3",
+ "g-4",
+ );
+ Accessibility.#features.forEach((feature) => {
+ const col = document.createElement("div");
+ col.classList.add("col");
- const card = document.createElement("div");
- card.classList.add("card");
+ const card = document.createElement("div");
+ card.classList.add("card");
- const cardHeader = document.createElement("div");
- cardHeader.classList.add("card-header");
- cardHeader.textContent = feature.title;
- card.appendChild(cardHeader);
+ const cardHeader = document.createElement("div");
+ cardHeader.classList.add("card-header");
+ cardHeader.textContent = feature.title;
+ card.appendChild(cardHeader);
- const cardBody = document.createElement("div");
- cardBody.classList.add("card-body");
- const description = document.createElement("p");
- description.classList.add("card-text");
- description.innerHTML = feature.description;
- cardBody.appendChild(description);
- card.appendChild(cardBody);
+ const cardBody = document.createElement("div");
+ cardBody.classList.add("card-body");
+ const description = document.createElement("p");
+ description.classList.add("card-text");
+ description.innerHTML = feature.description;
+ cardBody.appendChild(description);
+ card.appendChild(cardBody);
- col.appendChild(card);
- container.appendChild(col);
- });
+ col.appendChild(card);
+ container.appendChild(col);
+ });
- fragment.appendChild(container);
- return fragment;
- }
+ fragment.appendChild(container);
+ return fragment;
+ }
- static #wcagChecklist = [
- {
- criterion: "1.3.1 Info and Relationships",
- url: "https://www.w3.org/TR/WCAG22/#info-and-relationships",
- compliance: "Compliant",
- evidence:
+ static #wcagChecklist = [
+ {
+ criterion: "1.3.1 Info and Relationships",
+ url: "https://www.w3.org/TR/WCAG22/#info-and-relationships",
+ compliance: "Compliant",
+ evidence:
"role='switch', proper ARIA attributes, semantic structure",
- },
- {
- criterion: "1.4.4 Resize Text",
- url: "https://www.w3.org/TR/WCAG22/#resize-text",
- compliance: "Compliant",
- evidence: "Uses relative units, responsive design",
- },
- {
- criterion: "2.1.1 Keyboard",
- url: "https://www.w3.org/TR/WCAG22/#keyboard",
- compliance: "Compliant",
- evidence:
+ },
+ {
+ criterion: "1.4.4 Resize Text",
+ url: "https://www.w3.org/TR/WCAG22/#resize-text",
+ compliance: "Compliant",
+ evidence: "Uses relative units, responsive design",
+ },
+ {
+ criterion: "2.1.1 Keyboard",
+ url: "https://www.w3.org/TR/WCAG22/#keyboard",
+ compliance: "Compliant",
+ evidence:
"Responds to Space and Enter keys, all functionality keyboard accessible",
- },
- {
- criterion: "2.1.2 No Keyboard Trap",
- url: "https://www.w3.org/TR/WCAG22/#no-keyboard-trap",
- compliance: "Compliant",
- evidence:
+ },
+ {
+ criterion: "2.1.2 No Keyboard Trap",
+ url: "https://www.w3.org/TR/WCAG22/#no-keyboard-trap",
+ compliance: "Compliant",
+ evidence:
"tabindex=0 with proper focus management, users can navigate away",
- },
- {
- criterion: "2.1.4 Character Key Shortcuts",
- url: "https://www.w3.org/TR/WCAG22/#character-key-shortcuts",
- compliance: "Compliant",
- evidence: "No single-character shortcuts used",
- },
- {
- criterion: "2.4.3 Focus Order",
- url: "https://www.w3.org/TR/WCAG22/#focus-order",
- compliance: "Compliant",
- evidence: "tabindex respects DOM order",
- notice:
+ },
+ {
+ criterion: "2.1.4 Character Key Shortcuts",
+ url: "https://www.w3.org/TR/WCAG22/#character-key-shortcuts",
+ compliance: "Compliant",
+ evidence: "No single-character shortcuts used",
+ },
+ {
+ criterion: "2.4.3 Focus Order",
+ url: "https://www.w3.org/TR/WCAG22/#focus-order",
+ compliance: "Compliant",
+ evidence: "tabindex respects DOM order",
+ notice:
"Component follows logical DOM order; integration depends on page structure",
- },
- {
- criterion: "2.4.7 Focus Visible",
- url: "https://www.w3.org/TR/WCAG22/#focus-visible",
- compliance: "Partially",
- evidence: "Programmatic focus management implemented",
- notice:
+ },
+ {
+ criterion: "2.4.7 Focus Visible",
+ url: "https://www.w3.org/TR/WCAG22/#focus-visible",
+ compliance: "Partially",
+ evidence: "Programmatic focus management implemented",
+ notice:
"Visual focus indicators require CSS styling from consuming application, component defaults style meet criterion",
- },
- {
- criterion: "2.4.11 Focus Not Obscured (Minimum)",
- url: "https://www.w3.org/TR/WCAG22/#focus-not-obscured-minimum",
- compliance: "Partially",
- evidence: "Programmatic focus management implemented",
- notice:
+ },
+ {
+ criterion: "2.4.11 Focus Not Obscured (Minimum)",
+ url: "https://www.w3.org/TR/WCAG22/#focus-not-obscured-minimum",
+ compliance: "Partially",
+ evidence: "Programmatic focus management implemented",
+ notice:
"Component doesn't obscure its own focus, but page-level layout/styling may affect visibility",
- },
- {
- criterion: "2.4.12 Focus Not Obscured (Enhanced)",
- url: "https://www.w3.org/TR/WCAG22/#focus-not-obscured-enhanced",
- compliance: "Partially",
- evidence: "Programmatic focus management implemented",
- notice:
+ },
+ {
+ criterion: "2.4.12 Focus Not Obscured (Enhanced)",
+ url: "https://www.w3.org/TR/WCAG22/#focus-not-obscured-enhanced",
+ compliance: "Partially",
+ evidence: "Programmatic focus management implemented",
+ notice:
"Same as 2.4.11; component-level focus is clear but dependent on page context",
- },
- {
- criterion: "2.5.3 Label in Name",
- url: "https://www.w3.org/TR/WCAG22/#label-in-name",
- compliance: "Compliant",
- evidence: "aria-label matches visual label when provided",
- },
- {
- criterion: "3.2.1 On Focus",
- url: "https://www.w3.org/TR/WCAG22/#on-focus",
- compliance: "Compliant",
- evidence: "Focus does not trigger unexpected context changes",
- },
- {
- criterion: "3.3.2 Labels or Instructions",
- url: "https://www.w3.org/TR/WCAG22/#labels-or-instructions",
- compliance: "Compliant",
- evidence:
+ },
+ {
+ criterion: "2.5.3 Label in Name",
+ url: "https://www.w3.org/TR/WCAG22/#label-in-name",
+ compliance: "Compliant",
+ evidence: "aria-label matches visual label when provided",
+ },
+ {
+ criterion: "3.2.1 On Focus",
+ url: "https://www.w3.org/TR/WCAG22/#on-focus",
+ compliance: "Compliant",
+ evidence: "Focus does not trigger unexpected context changes",
+ },
+ {
+ criterion: "3.3.2 Labels or Instructions",
+ url: "https://www.w3.org/TR/WCAG22/#labels-or-instructions",
+ compliance: "Compliant",
+ evidence:
"Supports aria-label and aria-labelledby with fallback to default label",
- },
- {
- criterion: "4.1.1 Parsing",
- url: "https://www.w3.org/TR/WCAG22/#parsing",
- compliance: "Compliant",
- evidence: "Valid HTML, no duplicate IDs, proper nesting",
- },
- {
- criterion: "4.1.2 Name, Role, Value",
- url: "https://www.w3.org/TR/WCAG22/#name-role-value",
- compliance: "Compliant",
- evidence:
+ },
+ {
+ criterion: "4.1.1 Parsing",
+ url: "https://www.w3.org/TR/WCAG22/#parsing",
+ compliance: "Compliant",
+ evidence: "Valid HTML, no duplicate IDs, proper nesting",
+ },
+ {
+ criterion: "4.1.2 Name, Role, Value",
+ url: "https://www.w3.org/TR/WCAG22/#name-role-value",
+ compliance: "Compliant",
+ evidence:
"role='switch', aria-label | aria-labelledby for name, aria-checked for value",
- },
- {
- criterion: "4.1.3 Status Messages",
- url: "https://www.w3.org/TR/WCAG22/#status-messages",
- compliance: "Not Compliant",
- evidence:
+ },
+ {
+ criterion: "4.1.3 Status Messages",
+ url: "https://www.w3.org/TR/WCAG22/#status-messages",
+ compliance: "Not Compliant",
+ evidence:
"There is not aria-live, aria-atomic, or aria-relevant for dynamic state announcements",
- notice:
+ notice:
"State changes (ON/OFF/INDETERMINATE) are not announced via aria-live regions. Screen readers detect changes through aria-checked updates but not proactively announced.",
- },
- ];
+ },
+ ];
- static #wcagCompliance() {
- const fragment = document.createDocumentFragment();
+ static #wcagCompliance() {
+ const fragment = document.createDocumentFragment();
- const description = document.createElement("p");
- description.innerHTML = `Bootstrap Toggle adheres to WCAG 2.2 AA standards by implementing proper ARIA roles and attributes, ensuring that all users, including those with disabilities, can effectively interact with toggle switches.`;
+ const description = document.createElement("p");
+ description.innerHTML = "Bootstrap Toggle adheres to WCAG 2.2 AA standards by implementing proper ARIA roles and attributes, ensuring that all users, including those with disabilities, can effectively interact with toggle switches.";
- const list = document.createElement("ul");
- list.classList.add("list-group", "list-group-flush");
- Accessibility.#wcagChecklist.forEach((item) => {
- const listItem = document.createElement("li");
- listItem.classList.add("list-group-item");
+ const list = document.createElement("ul");
+ list.classList.add("list-group", "list-group-flush");
+ Accessibility.#wcagChecklist.forEach((item) => {
+ const listItem = document.createElement("li");
+ listItem.classList.add("list-group-item");
- const header = document.createElement("div");
- header.classList.add(
- "d-flex",
- "justify-content-start",
- "align-items-center",
- "gap-2",
- );
+ const header = document.createElement("div");
+ header.classList.add(
+ "d-flex",
+ "justify-content-start",
+ "align-items-center",
+ "gap-2",
+ );
- const url = document.createElement("a");
- url.classList.add("text-decoration-none");
- url.href = item.url;
- url.innerHTML = ``;
- url.target = "_blank";
- header.appendChild(url);
+ const url = document.createElement("a");
+ url.classList.add("text-decoration-none");
+ url.href = item.url;
+ url.innerHTML = "";
+ url.target = "_blank";
+ header.appendChild(url);
- const criterionText = document.createElement("strong");
- criterionText.innerHTML = item.criterion;
- header.appendChild(criterionText);
+ const criterionText = document.createElement("strong");
+ criterionText.innerHTML = item.criterion;
+ header.appendChild(criterionText);
- const badge = document.createElement("span");
- badge.classList.add("badge");
- if (item.compliance === "Compliant") {
- badge.classList.add("bg-success");
- } else if (item.compliance === "Partially") {
- badge.classList.add("bg-warning");
- } else {
- badge.classList.add("bg-danger");
- }
- badge.textContent = item.compliance;
- header.appendChild(badge);
- listItem.appendChild(header);
+ const badge = document.createElement("span");
+ badge.classList.add("badge");
+ if (item.compliance === "Compliant") {
+ badge.classList.add("bg-success");
+ } else if (item.compliance === "Partially") {
+ badge.classList.add("bg-warning");
+ } else {
+ badge.classList.add("bg-danger");
+ }
+ badge.textContent = item.compliance;
+ header.appendChild(badge);
+ listItem.appendChild(header);
- const evidence = document.createElement("p");
- evidence.classList.add("m-0");
- evidence.innerHTML = item.evidence;
- listItem.appendChild(evidence);
+ const evidence = document.createElement("p");
+ evidence.classList.add("m-0");
+ evidence.innerHTML = item.evidence;
+ listItem.appendChild(evidence);
- if (item.notice) {
- const notice = document.createElement("p");
- notice.classList.add("m-0");
- notice.innerHTML = `${item.notice}`;
- listItem.appendChild(notice);
- }
+ if (item.notice) {
+ const notice = document.createElement("p");
+ notice.classList.add("m-0");
+ notice.innerHTML = `${item.notice}`;
+ listItem.appendChild(notice);
+ }
- list.appendChild(listItem);
- });
+ list.appendChild(listItem);
+ });
- fragment.appendChild(description);
- fragment.appendChild(list);
- return fragment;
- }
+ fragment.appendChild(description);
+ fragment.appendChild(list);
+ return fragment;
+ }
}
export default Accessibility;
diff --git a/docs/src/js/components/documentation/Api.js b/docs/src/js/components/documentation/Api.js
index f39757f5..c76570be 100644
--- a/docs/src/js/components/documentation/Api.js
+++ b/docs/src/js/components/documentation/Api.js
@@ -6,15 +6,15 @@ import State from "./api/State";
import DocSection from "./DocSection";
class Api extends DocSection {
- static build() {
- return super.build("api", "API", [
- Options.build(),
- Methods.build(),
- InputInteraction.build(),
- State.build(),
- Rerender.build(),
- ]);
- }
+ static build() {
+ return super.build("api", "API", [
+ Options.build(),
+ Methods.build(),
+ InputInteraction.build(),
+ State.build(),
+ Rerender.build(),
+ ]);
+ }
}
export default Api;
diff --git a/docs/src/js/components/documentation/DevTools.js b/docs/src/js/components/documentation/DevTools.js
new file mode 100644
index 00000000..ac6de5c4
--- /dev/null
+++ b/docs/src/js/components/documentation/DevTools.js
@@ -0,0 +1,12 @@
+import Monitoring from "./devtools/Monitoring";
+import DocSection from "./DocSection";
+
+class DevTools extends DocSection {
+ static build() {
+ return super.build("devtools", "Developer Tools", [
+ Monitoring.build(),
+ ]);
+ }
+}
+
+export default DevTools;
diff --git a/docs/src/js/components/documentation/Distribution.js b/docs/src/js/components/documentation/Distribution.js
index 70be81db..652c27e8 100644
--- a/docs/src/js/components/documentation/Distribution.js
+++ b/docs/src/js/components/documentation/Distribution.js
@@ -2,104 +2,104 @@ import DocArticle from "./DocArticle";
import DocSection from "./DocSection";
class Distribution extends DocSection {
- static headers = ["Bootstrap Support", "Plugin Last Release", "End Of Life"];
- static entries = [
- { bootstrap: "5", plugin: "5", eol: "5" },
- { bootstrap: "4", plugin: "4", eol: "4" },
- { bootstrap: "3", plugin: "3", eol: "3" },
- ];
+ static headers = ["Bootstrap Support", "Plugin Last Release", "End Of Life"];
+ static entries = [
+ { bootstrap: "5", plugin: "5", eol: "5" },
+ { bootstrap: "4", plugin: "4", eol: "4" },
+ { bootstrap: "3", plugin: "3", eol: "3" },
+ ];
- static build() {
- return super.build(
- "distribution",
- "Library Distributions",
- [
- DocArticle.build({
- description: Distribution.#table(),
- }),
- ],
- "mb-3"
- );
- }
+ static build() {
+ return super.build(
+ "distribution",
+ "Library Distributions",
+ [
+ DocArticle.build({
+ description: Distribution.#table(),
+ }),
+ ],
+ "mb-3"
+ );
+ }
- static #table() {
- const container = document.createElement("div");
- container.className = "table-responsive";
+ static #table() {
+ const container = document.createElement("div");
+ container.className = "table-responsive";
- const table = document.createElement("table");
- table.className = "table table-striped table-condensed mb-0";
+ const table = document.createElement("table");
+ table.className = "table table-striped table-condensed mb-0";
- const caption = document.createElement("caption");
- caption.textContent = "Library Distributions";
+ const caption = document.createElement("caption");
+ caption.textContent = "Library Distributions";
- table.append(
- caption,
- Distribution.#tableHeader(),
- Distribution.#tableBody()
- );
- container.appendChild(table);
- return container;
- }
+ table.append(
+ caption,
+ Distribution.#tableHeader(),
+ Distribution.#tableBody()
+ );
+ container.appendChild(table);
+ return container;
+ }
- static #tableHeader() {
- const thead = document.createElement("thead");
- const row = document.createElement("tr");
+ static #tableHeader() {
+ const thead = document.createElement("thead");
+ const row = document.createElement("tr");
- Distribution.headers.forEach((headerText) => {
- const th = document.createElement("th");
- th.textContent = headerText;
- row.appendChild(th);
- });
+ Distribution.headers.forEach((headerText) => {
+ const th = document.createElement("th");
+ th.textContent = headerText;
+ row.appendChild(th);
+ });
- thead.appendChild(row);
- return thead;
- }
+ thead.appendChild(row);
+ return thead;
+ }
- static #tableBody() {
- const tbody = document.createElement("tbody");
- Distribution.entries.forEach((entry) => {
- const row = document.createElement("tr");
- const tdBootstrap = document.createElement("td");
- const aBootstrap = document.createElement("a");
- aBootstrap.href = `https://getbootstrap.com/docs/${entry.bootstrap}.0`;
- aBootstrap.target = "_blank";
- aBootstrap.rel = "noopener noreferrer";
- aBootstrap.title = `Bootstrap ${entry.bootstrap}`;
- const imgBootstrap = document.createElement("img");
- imgBootstrap.src = `https://img.shields.io/static/v1?label=bootstrap&message=%5Ev${entry.bootstrap}.0.0&color=informational&logo=bootstrap&logoColor=white`;
- imgBootstrap.alt = `Bootstrap ${entry.bootstrap}`;
- aBootstrap.appendChild(imgBootstrap);
- tdBootstrap.appendChild(aBootstrap);
+ static #tableBody() {
+ const tbody = document.createElement("tbody");
+ Distribution.entries.forEach((entry) => {
+ const row = document.createElement("tr");
+ const tdBootstrap = document.createElement("td");
+ const aBootstrap = document.createElement("a");
+ aBootstrap.href = `https://getbootstrap.com/docs/${entry.bootstrap}.0`;
+ aBootstrap.target = "_blank";
+ aBootstrap.rel = "noopener noreferrer";
+ aBootstrap.title = `Bootstrap ${entry.bootstrap}`;
+ const imgBootstrap = document.createElement("img");
+ imgBootstrap.src = `https://img.shields.io/static/v1?label=bootstrap&message=%5Ev${entry.bootstrap}.0.0&color=informational&logo=bootstrap&logoColor=white`;
+ imgBootstrap.alt = `Bootstrap ${entry.bootstrap}`;
+ aBootstrap.appendChild(imgBootstrap);
+ tdBootstrap.appendChild(aBootstrap);
- const tdPlugin = document.createElement("td");
- const aPlugin = document.createElement("a");
- aPlugin.href = `https://github.com/palcarazm/bootstrap5-toggle/releases`;
- aPlugin.target = "_blank";
- aPlugin.rel = "noopener noreferrer";
- aPlugin.title = `bs-toggle v${entry.plugin}`;
- const imgPlugin = document.createElement("img");
- imgPlugin.src = `https://img.shields.io/github/package-json/v/palcarazm/bootstrap5-toggle/v${entry.plugin}?logo=github`;
- imgPlugin.alt = `bs-toggle v${entry.plugin}`;
- aPlugin.appendChild(imgPlugin);
- tdPlugin.appendChild(aPlugin);
+ const tdPlugin = document.createElement("td");
+ const aPlugin = document.createElement("a");
+ aPlugin.href = "https://github.com/palcarazm/bootstrap5-toggle/releases";
+ aPlugin.target = "_blank";
+ aPlugin.rel = "noopener noreferrer";
+ aPlugin.title = `bs-toggle v${entry.plugin}`;
+ const imgPlugin = document.createElement("img");
+ imgPlugin.src = `https://img.shields.io/github/package-json/v/palcarazm/bootstrap5-toggle/v${entry.plugin}?logo=github`;
+ imgPlugin.alt = `bs-toggle v${entry.plugin}`;
+ aPlugin.appendChild(imgPlugin);
+ tdPlugin.appendChild(aPlugin);
- const tdEOL = document.createElement("td");
- const aEOL = document.createElement("a");
- aEOL.href = `https://github.com/palcarazm/bootstrap5-toggle/security/policy`;
- aEOL.target = "_blank";
- aEOL.rel = "noopener noreferrer";
- aEOL.title = `End of Life`;
- const imgEOL = document.createElement("img");
- imgEOL.src = `https://img.shields.io/endpoint?url=https%3A%2F%2Fpalcarazm.github.io%2Fbootstrap5-toggle%2Fapi%2Feol%2Fv${entry.eol}`;
- imgEOL.alt = `EOL v${entry.eol}`;
- aEOL.appendChild(imgEOL);
- tdEOL.appendChild(aEOL);
+ const tdEOL = document.createElement("td");
+ const aEOL = document.createElement("a");
+ aEOL.href = "https://github.com/palcarazm/bootstrap5-toggle/security/policy";
+ aEOL.target = "_blank";
+ aEOL.rel = "noopener noreferrer";
+ aEOL.title = "End of Life";
+ const imgEOL = document.createElement("img");
+ imgEOL.src = `https://img.shields.io/endpoint?url=https%3A%2F%2Fpalcarazm.github.io%2Fbootstrap5-toggle%2Fapi%2Feol%2Fv${entry.eol}`;
+ imgEOL.alt = `EOL v${entry.eol}`;
+ aEOL.appendChild(imgEOL);
+ tdEOL.appendChild(aEOL);
- row.append(tdBootstrap, tdPlugin, tdEOL);
- tbody.appendChild(row);
- });
- return tbody;
- }
+ row.append(tdBootstrap, tdPlugin, tdEOL);
+ tbody.appendChild(row);
+ });
+ return tbody;
+ }
}
export default Distribution;
diff --git a/docs/src/js/components/documentation/DocAlert.js b/docs/src/js/components/documentation/DocAlert.js
index c91d2ecf..5d9f3f42 100644
--- a/docs/src/js/components/documentation/DocAlert.js
+++ b/docs/src/js/components/documentation/DocAlert.js
@@ -1,54 +1,54 @@
import VersionPill from "../VersionPill";
class DocAlert {
- static build({ type, title, content, versionPill = null }) {
- const alert = document.createElement("div");
- alert.className = `alert alert-${type}`;
+ static build({ type, title, content, versionPill = null }) {
+ const alert = document.createElement("div");
+ alert.className = `alert alert-${type}`;
- const alertBody = document.createElement("div");
- alertBody.innerHTML = content;
+ const alertBody = document.createElement("div");
+ alertBody.innerHTML = content;
- alert.append(DocAlert.#alertHeader(type, title, versionPill), alertBody);
- return alert;
- }
+ alert.append(DocAlert.#alertHeader(type, title, versionPill), alertBody);
+ return alert;
+ }
- static #alertHeader(type, title, versionPill) {
- const header = document.createElement("div");
- header.className =
+ static #alertHeader(type, title, versionPill) {
+ const header = document.createElement("div");
+ header.className =
"d-flex justify-content-between align-items-center alert-heading";
- let icon = document.createElement("i");
- switch (type) {
- case "info":
- icon.className = "fa-solid fa-info-circle";
- break;
- case "success":
- icon.className = "fa-solid fa-circle-check";
- break;
- case "warning":
- icon.className = "fa-solid fa-exclamation-circle";
- break;
- case "danger":
- icon.className = "fa-solid fa-exclamation-triangle";
- break;
- default:
- icon = null;
- break;
+ let icon = document.createElement("i");
+ switch (type) {
+ case "info":
+ icon.className = "fa-solid fa-info-circle";
+ break;
+ case "success":
+ icon.className = "fa-solid fa-circle-check";
+ break;
+ case "warning":
+ icon.className = "fa-solid fa-exclamation-circle";
+ break;
+ case "danger":
+ icon.className = "fa-solid fa-exclamation-triangle";
+ break;
+ default:
+ icon = null;
+ break;
+ }
+
+ const col = document.createElement("div");
+ if (icon) col.appendChild(icon);
+ const titleContainer = document.createElement("span");
+ titleContainer.className = "text-uppercase fw-bold ms-1";
+ titleContainer.textContent = title;
+ col.appendChild(titleContainer);
+
+ header.appendChild(col);
+
+ if (versionPill) header.appendChild(VersionPill.build(versionPill));
+
+ return header;
}
-
- const col = document.createElement("div");
- if (icon) col.appendChild(icon);
- const titleContainer = document.createElement("span");
- titleContainer.className = "text-uppercase fw-bold ms-1";
- titleContainer.textContent = title;
- col.appendChild(titleContainer);
-
- header.appendChild(col);
-
- if (versionPill) header.appendChild(VersionPill.build(versionPill));
-
- return header;
- }
}
export default DocAlert;
diff --git a/docs/src/js/components/documentation/DocArticle.js b/docs/src/js/components/documentation/DocArticle.js
index be1a4053..6b398135 100644
--- a/docs/src/js/components/documentation/DocArticle.js
+++ b/docs/src/js/components/documentation/DocArticle.js
@@ -5,53 +5,59 @@ import VersionPill from "../VersionPill";
import DocAlert from "./DocAlert";
class DocArticle {
- static build({
- title = null,
- className = "",
- badge = null,
- versionPill = null,
- description = null,
- example = [],
- codePanel = null,
- codeBlock = null,
- alert = null,
- }) {
- const docArticle = document.createElement("article");
- docArticle.className = `ps-2 px-2 border-start border-2 ${className}`;
-
- if (title)
- docArticle.appendChild(
- DocArticle.#articleHeader(title, badge, versionPill)
- );
-
- if (description) docArticle.appendChild(description);
-
- if (codePanel && codeBlock)
- throw new Error("CodePanel and CodeBlock are mutually exclusive.");
- if (codePanel)
- docArticle.appendChild(CodePanel.build({ example, ...codePanel }));
- if (codeBlock)
- docArticle.appendChild(CodeBlock.build({ example, ...codeBlock }));
-
- if (alert) docArticle.appendChild(DocAlert.build(alert));
-
- return docArticle;
- }
-
- static #articleHeader(title, badge, versionPill) {
- const header = document.createElement("div");
- header.className = "d-flex justify-content-between align-items-center";
- const titleContainer = document.createElement("h3");
- titleContainer.className = "text-secondary";
- titleContainer.textContent = title;
- header.appendChild(titleContainer);
-
- if (badge) header.appendChild(Badge.build(badge));
-
- if (versionPill) header.appendChild(VersionPill.build(versionPill));
-
- return header;
- }
+ static build({
+ title = null,
+ className = "",
+ badge = null,
+ versionPill = null,
+ description = null,
+ example = [],
+ codePanel = null,
+ codeBlock = null,
+ alert = null,
+ }) {
+ const docArticle = document.createElement("article");
+ docArticle.className = `ps-2 px-2 border-start border-2 ${className}`;
+
+ if (title)
+ docArticle.appendChild(
+ DocArticle.#articleHeader(title, badge, versionPill)
+ );
+
+ if (description) docArticle.appendChild(description);
+
+ if (codePanel && codeBlock)
+ throw new Error("CodePanel and CodeBlock are mutually exclusive.");
+ if (codePanel)
+ docArticle.appendChild(CodePanel.build({ example, ...codePanel }));
+ if (codeBlock)
+ docArticle.appendChild(CodeBlock.build({ example, ...codeBlock }));
+
+ if (alert) docArticle.appendChild(DocAlert.build(alert));
+
+ return docArticle;
+ }
+
+ static #articleHeader(title, badge, versionPill) {
+ const header = document.createElement("div");
+ header.className = "d-flex justify-content-between align-items-center";
+ const titleContainer = document.createElement("h3");
+ titleContainer.className = "text-secondary";
+ titleContainer.textContent = title;
+ header.appendChild(titleContainer);
+
+ if (badge) header.appendChild(Badge.build(badge));
+
+ if (versionPill) header.appendChild(VersionPill.build(versionPill));
+
+ return header;
+ }
+
+ static fragment(...nodes) {
+ const fragment = document.createDocumentFragment();
+ nodes.forEach((node) => fragment.appendChild(node));
+ return fragment;
+ }
}
export default DocArticle;
diff --git a/docs/src/js/components/documentation/DocSection.js b/docs/src/js/components/documentation/DocSection.js
index 3bd08ee8..cbcd7426 100644
--- a/docs/src/js/components/documentation/DocSection.js
+++ b/docs/src/js/components/documentation/DocSection.js
@@ -1,16 +1,16 @@
class DocSection {
- static build(name, title, HTMLElements, className = "") {
- const section = document.createElement("section");
- section.id = name;
- section.className = `container ${className}`;
- section.append(DocSection.#header(title), ...HTMLElements);
- return section;
- }
- static #header(title) {
- const header = document.createElement("h2");
- header.textContent = title;
- return header;
- }
+ static build(name, title, HTMLElements, className = "") {
+ const section = document.createElement("section");
+ section.id = name;
+ section.className = `container ${className}`;
+ section.append(DocSection.#header(title), ...HTMLElements);
+ return section;
+ }
+ static #header(title) {
+ const header = document.createElement("h2");
+ header.textContent = title;
+ return header;
+ }
}
export default DocSection;
diff --git a/docs/src/js/components/documentation/Events.js b/docs/src/js/components/documentation/Events.js
index 36e16467..3d34f590 100644
--- a/docs/src/js/components/documentation/Events.js
+++ b/docs/src/js/components/documentation/Events.js
@@ -1,16 +1,20 @@
import DocSection from "./DocSection";
import CustomEvents from "./events/CustomEvents";
import EventPropagation from "./events/EventPropagation";
+import LifecycleEvents from "./events/LifecycleEvents";
+import ChainableSubscription from "./events/ChainableSubscription";
import SilencedActions from "./events/SilencedActions";
class Events extends DocSection {
- static build() {
- return super.build("events", "Events", [
- EventPropagation.build(),
- CustomEvents.build(),
- SilencedActions.build(),
- ]);
- }
+ static build() {
+ return super.build("events", "Events", [
+ EventPropagation.build(),
+ CustomEvents.build(),
+ LifecycleEvents.build(),
+ ChainableSubscription.build(),
+ SilencedActions.build(),
+ ]);
+ }
}
export default Events;
diff --git a/docs/src/js/components/documentation/Features.js b/docs/src/js/components/documentation/Features.js
index a9be4660..fb34a311 100644
--- a/docs/src/js/components/documentation/Features.js
+++ b/docs/src/js/components/documentation/Features.js
@@ -15,24 +15,24 @@ import Tooltip from "./features/Tooltip";
import Tristate from "./features/Tristate";
class Features extends DocSection {
- static build() {
- return super.build("features", "Features", [
- Size.build(),
- CustomSize.build(),
- Tristate.build(),
- Colors.build(),
- OutlineColors.build(),
- CustomText.build(),
- CustomTitle.build(),
- Tooltip.build(),
- CustomStyle.build(),
- AnimationSpeed.build(),
- KeyboardInteraction.build(),
- StateStatus.build(),
- CustomFormValue.build(),
- FormLayout.build(),
- ]);
- }
+ static build() {
+ return super.build("features", "Features", [
+ Size.build(),
+ CustomSize.build(),
+ Tristate.build(),
+ Colors.build(),
+ OutlineColors.build(),
+ CustomText.build(),
+ CustomTitle.build(),
+ Tooltip.build(),
+ CustomStyle.build(),
+ AnimationSpeed.build(),
+ KeyboardInteraction.build(),
+ StateStatus.build(),
+ CustomFormValue.build(),
+ FormLayout.build(),
+ ]);
+ }
}
export default Features;
diff --git a/docs/src/js/components/documentation/Installation.js b/docs/src/js/components/documentation/Installation.js
index 70e07e6b..7c101d73 100644
--- a/docs/src/js/components/documentation/Installation.js
+++ b/docs/src/js/components/documentation/Installation.js
@@ -2,72 +2,72 @@ import DocArticle from "./DocArticle";
import DocSection from "./DocSection";
class Installation extends DocSection {
- static build() {
- return super.build("installation", "Installation", [
- Installation.#cdn(),
- Installation.#github(),
- Installation.#npm(),
- Installation.#yarn(),
- ]);
- }
+ static build() {
+ return super.build("installation", "Installation", [
+ Installation.#cdn(),
+ Installation.#github(),
+ Installation.#npm(),
+ Installation.#yarn(),
+ ]);
+ }
- static #cdn() {
- const ecmas = `
+ static #cdn() {
+ const ecmas = `
`;
- const jquery = `
+ const jquery = `
`;
- return DocArticle.build({
- title: "CDN",
- badge: {
- name: "jsDelivr",
- href: "https://www.jsdelivr.com/package/npm/bootstrap5-toggle",
- imgSrc:
+ return DocArticle.build({
+ title: "CDN",
+ badge: {
+ name: "jsDelivr",
+ href: "https://www.jsdelivr.com/package/npm/bootstrap5-toggle",
+ imgSrc:
"https://img.shields.io/jsdelivr/npm/hm/bootstrap5-toggle?label=hits&logo=jsdelivr&logoColor=white",
- },
- codePanel: {
- name: "cdn",
- language: "html",
- contents: [ecmas, jquery],
- },
- });
- }
+ },
+ codePanel: {
+ name: "cdn",
+ language: "html",
+ contents: [ecmas, jquery],
+ },
+ });
+ }
- static #github() {
- return DocArticle.build({
- title: "Download from GitHub",
- badge: {
- name: "Latest release",
- href: "https://github.com/palcarazm/bootstrap5-toggle/releases",
- imgSrc:
+ static #github() {
+ return DocArticle.build({
+ title: "Download from GitHub",
+ badge: {
+ name: "Latest release",
+ href: "https://github.com/palcarazm/bootstrap5-toggle/releases",
+ imgSrc:
"https://img.shields.io/github/package-json/v/palcarazm/bootstrap5-toggle/v5?logo=github",
- },
- });
- }
+ },
+ });
+ }
- static #npm() {
- return DocArticle.build({
- title: "NPM",
- badge: {
- name: "NPM",
- href: "https://www.npmjs.com/package/bootstrap5-toggle",
- imgSrc: "https://img.shields.io/npm/dm/bootstrap5-toggle?logo=npm",
- },
- codeBlock: {
- language: "shell",
- code: `npm install bootstrap5-toggle@${versions.bootstrap5Toggle}`,
- },
- });
- }
+ static #npm() {
+ return DocArticle.build({
+ title: "NPM",
+ badge: {
+ name: "NPM",
+ href: "https://www.npmjs.com/package/bootstrap5-toggle",
+ imgSrc: "https://img.shields.io/npm/dm/bootstrap5-toggle?logo=npm",
+ },
+ codeBlock: {
+ language: "shell",
+ code: `npm install bootstrap5-toggle@${versions.bootstrap5Toggle}`,
+ },
+ });
+ }
- static #yarn() {
- return DocArticle.build({
- title: "Yarn",
- codeBlock: {
- language: "shell",
- code: `yarn add bootstrap5-toggle@${versions.bootstrap5Toggle}`,
- },
- });
- }
+ static #yarn() {
+ return DocArticle.build({
+ title: "Yarn",
+ codeBlock: {
+ language: "shell",
+ code: `yarn add bootstrap5-toggle@${versions.bootstrap5Toggle}`,
+ },
+ });
+ }
}
export default Installation;
diff --git a/docs/src/js/components/documentation/Usage.js b/docs/src/js/components/documentation/Usage.js
index a507740d..6c6f6aa5 100644
--- a/docs/src/js/components/documentation/Usage.js
+++ b/docs/src/js/components/documentation/Usage.js
@@ -2,41 +2,47 @@ import DocSection from "./DocSection";
import DocArticle from "./DocArticle";
class Usage extends DocSection {
- static build() {
- return super.build("usage", "Usage", [Usage.#html(), Usage.#js()]);
- }
-
- static #html() {
- const description = document.createElement("p");
- description.innerHTML = `Simply add data-toggle="toggle" to convert checkboxes into toggles.`;
-
- return DocArticle.build({
- title: "Initialize with HTML",
- description,
- codeBlock: {
- language: "html",
- code: ``,
- },
- });
- }
-
- static #js() {
- const description = document.createElement("p");
- description.innerHTML = `Simply call the bootstrapToggle method to convert checkboxes into toggles. See Options for additional colors, etc.
data-toggle=\"toggle\" to convert checkboxes into toggles.";
+
+ const asyncNote = document.createElement("p");
+ asyncNote.innerHTML = "[data-toggle=\"toggle\"] auto-init runs on window.onload and awaits init().then(attach) internally.";
+
+ return DocArticle.build({
+ title: "Initialize with HTML",
+ description: DocArticle.fragment(description, asyncNote),
+ codeBlock: {
+ language: "html",
+ code: "",
+ },
+ });
+ }
+
+ static #js() {
+ const description = document.createElement("p");
+ description.innerHTML = "Simply call the bootstrapToggle method to convert checkboxes into toggles. See Options for additional colors, etc.";
+
+ const asyncNote = document.createElement("p");
+ asyncNote.innerHTML = "element.bootstrapToggle() returns synchronously and starts the lifecycle in a microtask. element.bsToggle is set synchronously (in the constructor) but element.bsToggle.isAttached() is false until the microtask drains.";
+
+ const ecmas = "document.querySelector(mySelector).bootstrapToggle();";
+ const jquery = "$(mySelector).bootstrapToggle();";
+
+ return DocArticle.build({
+ title: "Initialize with JavaScript",
+ description: DocArticle.fragment(description, asyncNote),
+ codePanel: {
+ name: "usage-js",
+ language: "javascript",
+ contents: [ecmas, jquery],
+ },
+ });
+ }
}
export default Usage;
diff --git a/docs/src/js/components/documentation/api/InputInteraction.js b/docs/src/js/components/documentation/api/InputInteraction.js
index f33d0727..c82c3c7c 100644
--- a/docs/src/js/components/documentation/api/InputInteraction.js
+++ b/docs/src/js/components/documentation/api/InputInteraction.js
@@ -1,167 +1,176 @@
import DocArticle from "../DocArticle";
class InputInteraction extends DocArticle {
- static #interactions = [
- {
- action: "checked",
- function: "myInput.checked = true",
- description: "Sets the toggle to 'On' state",
- demo: (input) => {
- input.checked = true;
- },
- },
- {
- action: "unchecked",
- function: "myInput.checked = false",
- description: "Sets the toggle to 'Off' state",
- demo: (input) => {
- input.checked = false;
- },
- },
- {
- action: "indeterminate",
- function: "myInput.indeterminate = true",
- description: "Sets the toggle to 'indeterminate' state",
- demo: (input) => {
- input.indeterminate = true;
- },
- },
- {
- action: "determinate",
- function: "myInput.indeterminate = false",
- description:
+ static #interactions = [
+ {
+ action: "checked",
+ function: "myInput.checked = true",
+ description: "Sets the toggle to 'On' state",
+ demo: (input) => {
+ input.checked = true;
+ },
+ },
+ {
+ action: "unchecked",
+ function: "myInput.checked = false",
+ description: "Sets the toggle to 'Off' state",
+ demo: (input) => {
+ input.checked = false;
+ },
+ },
+ {
+ action: "indeterminate",
+ function: "myInput.indeterminate = true",
+ description: "Sets the toggle to 'indeterminate' state",
+ demo: (input) => {
+ input.indeterminate = true;
+ },
+ },
+ {
+ action: "determinate",
+ function: "myInput.indeterminate = false",
+ description:
"Sets the toggle to the previous 'determinate' state ('on' or 'off')",
- demo: (input) => {
- input.indeterminate = false;
- },
- },
- {
- action: "enable",
- function: "myInput.disabled = false",
- description: "Enables the toggle",
- demo: (input) => {
- input.disabled = false;
- },
- },
- {
- action: "disable",
- function: "myInput.disabled = true",
- description: "Disables the toggle",
- demo: (input) => {
- input.disabled = true;
- },
- },
- {
- action: "read-only",
- function: "myInput.readOnly = true",
- description:
+ demo: (input) => {
+ input.indeterminate = false;
+ },
+ },
+ {
+ action: "enable",
+ function: "myInput.disabled = false",
+ description: "Enables the toggle",
+ demo: (input) => {
+ input.disabled = false;
+ },
+ },
+ {
+ action: "disable",
+ function: "myInput.disabled = true",
+ description: "Disables the toggle",
+ demo: (input) => {
+ input.disabled = true;
+ },
+ },
+ {
+ action: "read-only",
+ function: "myInput.readOnly = true",
+ description:
"Disables the toggle but the checkbox stay readable in form data.",
- demo: (input) => {
- input.readOnly = true;
- },
- },
- {
- action: "read-write",
- function: "myInput.readOnly = false",
- description:
+ demo: (input) => {
+ input.readOnly = true;
+ },
+ },
+ {
+ action: "read-write",
+ function: "myInput.readOnly = false",
+ description:
"Removes the readonly state, enabling user interaction with the toggle.",
- demo: (input) => {
- input.readOnly = false;
- },
- },
- ];
-
- static build() {
- const input = document.createElement("input");
- input.setAttribute("type", "checkbox");
- input.setAttribute("id", "api-input-interaction");
- input.setAttribute("checked", "");
- input.setAttribute("tristate", "");
- input.dataset.toggle = "toggle";
-
- return super.build({
- title: "Input Interaction",
- description: InputInteraction.#description(input),
- codeBlock: {
- language: "html",
- code: `
+ demo: (input) => {
+ input.readOnly = false;
+ },
+ },
+ ];
+
+ static build() {
+ const input = document.createElement("input");
+ input.setAttribute("type", "checkbox");
+ input.setAttribute("id", "api-input-interaction");
+ input.setAttribute("checked", "");
+ input.setAttribute("tristate", "");
+ input.dataset.toggle = "toggle";
+
+ return super.build({
+ title: "Input Interaction",
+ description: InputInteraction.#description(input),
+ codeBlock: {
+ language: "html",
+ code: `
`,
- },
- example: [input],
- });
- }
+ },
+ example: [input],
+ });
+ }
- static #description(input) {
- const description = document.createElement("div");
+ static #description(input) {
+ const description = document.createElement("div");
- const paragraph = document.createElement("p");
- paragraph.innerHTML =
+ const paragraph = document.createElement("p");
+ paragraph.innerHTML =
"Interact with the input elements dispatch changes to the toggle:";
- description.append(paragraph, InputInteraction.#table(input));
-
- return description;
- }
-
- static #table(input) {
- const table = document.createElement("table");
- table.className = "table table-striped table-condensed";
- const caption = document.createElement("caption");
- caption.textContent = "Input interaction demo";
- table.append(
- caption,
- InputInteraction.#thead(),
- InputInteraction.#tbody(input),
- );
-
- return table;
- }
-
- static #thead() {
- const thead = document.createElement("thead");
- const tr = document.createElement("tr");
- tr.append(
- ...["Action", "Example", "Description", "Demo"].map((label) => {
- const th = document.createElement("th");
- th.textContent = label;
- return th;
- }),
- );
- thead.append(tr);
- return thead;
- }
-
- static #tbody(input) {
- const tbody = document.createElement("tbody");
-
- const trs = InputInteraction.#interactions.map(
- ({ action, function: func, description, demo }) => {
- const td1 = document.createElement("td");
- td1.innerHTML = `${action}`;
-
- const td2 = document.createElement("td");
- td2.innerHTML = `${func}`;
-
- const td3 = document.createElement("td");
- td3.textContent = description;
-
- const td4 = document.createElement("td");
- const button = document.createElement("button");
- button.className = "btn btn-outline-dark btn-sm w-100";
- button.textContent = action;
- button.onclick = () => {
- demo(input);
- };
- td4.append(button);
+ const footnote = document.createElement("p");
+ footnote.innerHTML =
+ "These demos assume the toggle is already attached. If calling immediately after .bootstrapToggle(), await input.bsToggle.attach() first or call .update().";
+
+ description.append(
+ paragraph,
+ InputInteraction.#table(input),
+ footnote
+ );
+
+ return description;
+ }
+
+ static #table(input) {
+ const table = document.createElement("table");
+ table.className = "table table-striped table-condensed";
+ const caption = document.createElement("caption");
+ caption.textContent = "Input interaction demo";
+ table.append(
+ caption,
+ InputInteraction.#thead(),
+ InputInteraction.#tbody(input),
+ );
+
+ return table;
+ }
+
+ static #thead() {
+ const thead = document.createElement("thead");
const tr = document.createElement("tr");
- tr.append(td1, td2, td3, td4);
- return tr;
- },
- );
-
- tbody.append(...trs);
- return tbody;
- }
+ tr.append(
+ ...["Action", "Example", "Description", "Demo"].map((label) => {
+ const th = document.createElement("th");
+ th.textContent = label;
+ return th;
+ }),
+ );
+ thead.append(tr);
+ return thead;
+ }
+
+ static #tbody(input) {
+ const tbody = document.createElement("tbody");
+
+ const trs = InputInteraction.#interactions.map(
+ ({ action, function: func, description, demo }) => {
+ const td1 = document.createElement("td");
+ td1.innerHTML = `${action}`;
+
+ const td2 = document.createElement("td");
+ td2.innerHTML = `${func}`;
+
+ const td3 = document.createElement("td");
+ td3.textContent = description;
+
+ const td4 = document.createElement("td");
+ const button = document.createElement("button");
+ button.className = "btn btn-outline-dark btn-sm w-100";
+ button.textContent = action;
+ button.onclick = () => {
+ demo(input);
+ };
+ td4.append(button);
+
+ const tr = document.createElement("tr");
+ tr.append(td1, td2, td3, td4);
+ return tr;
+ },
+ );
+
+ tbody.append(...trs);
+ return tbody;
+ }
}
export default InputInteraction;
diff --git a/docs/src/js/components/documentation/api/Methods.js b/docs/src/js/components/documentation/api/Methods.js
index cf7f0089..d4cd657d 100644
--- a/docs/src/js/components/documentation/api/Methods.js
+++ b/docs/src/js/components/documentation/api/Methods.js
@@ -1,151 +1,168 @@
import DocArticle from "../DocArticle";
class Methods extends DocArticle {
- static #methods = [
- {
- method: "initialize",
- params: null,
- description: "Initializes the toggle plugin with options",
- },
- {
- method: "destroy",
- params: "destroy",
- description: "Destroys the toggle",
- },
- {
- method: "rerender",
- params: "rerender",
- description: "Rerenders the toggle",
- },
- {
- method: "on",
- params: "on",
- description: "Sets the toggle to 'On' state",
- },
- {
- method: "off",
- params: "off",
- description: "Sets the toggle to 'Off' state",
- },
- {
- method: "toggle",
- params: "toggle",
- description: "Toggles the state of the toggle",
- },
- {
- method: "indeterminate",
- params: "indeterminate",
- description: "Sets the toggle to 'indeterminate' state",
- },
- {
- method: "determinate",
- params: "determinate",
- description:
+ static #methods = [
+ {
+ method: "initialize",
+ params: null,
+ description: "Initializes the toggle plugin with options",
+ },
+ {
+ method: "destroy",
+ params: "destroy",
+ description: "Destroys the toggle",
+ },
+ {
+ method: "rerender",
+ params: "rerender",
+ description: "Rerenders the toggle",
+ },
+ {
+ method: "on",
+ params: "on",
+ description: "Sets the toggle to 'On' state",
+ },
+ {
+ method: "off",
+ params: "off",
+ description: "Sets the toggle to 'Off' state",
+ },
+ {
+ method: "toggle",
+ params: "toggle",
+ description: "Toggles the state of the toggle",
+ },
+ {
+ method: "indeterminate",
+ params: "indeterminate",
+ description: "Sets the toggle to 'indeterminate' state",
+ },
+ {
+ method: "determinate",
+ params: "determinate",
+ description:
"Sets the toggle to the previous 'determinate' state ('on' or 'off')",
- },
- {
- method: "enable",
- params: "enable",
- description: "Enables the toggle",
- },
- {
- method: "disable",
- params: "disable",
- description: "Disables the toggle",
- },
- {
- method: "readonly",
- params: "readonly",
- description:
+ },
+ {
+ method: "enable",
+ params: "enable",
+ description: "Enables the toggle",
+ },
+ {
+ method: "disable",
+ params: "disable",
+ description: "Disables the toggle",
+ },
+ {
+ method: "readonly",
+ params: "readonly",
+ description:
"Disables the toggle but the checkbox stay readable in form data.",
- },
- ];
-
- static build() {
- const input = document.createElement("input");
- input.setAttribute("type", "checkbox");
- input.setAttribute("id", "api-methods-toggle");
- input.setAttribute("checked", "");
-
- return super.build({
- title: "Methods",
- description: Methods.#description(input),
- codeBlock: {
- language: "html",
- code: `
+ },
+ ];
+
+ static build() {
+ const input = document.createElement("input");
+ input.setAttribute("type", "checkbox");
+ input.setAttribute("id", "api-methods-toggle");
+ input.setAttribute("checked", "");
+
+ return super.build({
+ title: "Methods",
+ description: Methods.#description(input),
+ codeBlock: {
+ language: "html",
+ code: `
`,
- },
- example: [input],
- });
- }
+ },
+ example: [input],
+ alert: Methods.#asyncAlert(),
+ });
+ }
- static #description(input) {
- const description = document.createElement("div");
+ static #description(input) {
+ const description = document.createElement("div");
- const paragraph = document.createElement("p");
- paragraph.innerHTML =
+ const paragraph = document.createElement("p");
+ paragraph.innerHTML =
"Methods can be used to control toggles directly. The following methods are available in the following way:";
- description.append(paragraph, Methods.#table(input));
-
- return description;
- }
-
- static #table(input) {
- const table = document.createElement("table");
- table.className = "table table-striped table-condensed";
- const caption = document.createElement("caption");
- caption.textContent = "API methods demo";
- table.append(caption, Methods.#thead(), Methods.#tbody(input));
-
- return table;
- }
-
- static #thead() {
- const thead = document.createElement("thead");
- const tr = document.createElement("tr");
- tr.append(
- ...["Method", "Example", "Description", "Demo"].map((label) => {
- const th = document.createElement("th");
- th.textContent = label;
- return th;
- })
- );
- thead.append(tr);
- return thead;
- }
-
- static #tbody(input) {
- const tbody = document.createElement("tbody");
-
- const trs = Methods.#methods.map(({ method, params, description }) => {
- const td1 = document.createElement("td");
- td1.innerHTML = `${method}`;
-
- const td2 = document.createElement("td");
- td2.innerHTML = params
- ? `myToggle.bootstrapToggle("${params}")`
- : `myToggle.bootstrapToggle()`;
-
- const td3 = document.createElement("td");
- td3.textContent = description;
-
- const td4 = document.createElement("td");
- const button = document.createElement("button");
- button.className = "btn btn-outline-dark btn-sm w-100";
- button.textContent = method;
- button.onclick = () => {
- input.bootstrapToggle(params);
- };
- td4.append(button);
-
- const tr = document.createElement("tr");
- tr.append(td1, td2, td3, td4);
- return tr;
- });
-
- tbody.append(...trs);
- return tbody;
- }
+
+ description.append(
+ paragraph,
+ Methods.#table(input),
+ );
+
+ return description;
+ }
+
+ static #table(input) {
+ const table = document.createElement("table");
+ table.className = "table table-striped table-condensed";
+ const caption = document.createElement("caption");
+ caption.textContent = "API methods demo";
+ table.append(caption, Methods.#thead(), Methods.#tbody(input));
+
+ return table;
+ }
+
+ static #thead() {
+ const thead = document.createElement("thead");
+ const tr = document.createElement("tr");
+ tr.append(
+ ...["Method", "Example", "Description", "Demo"].map((label) => {
+ const th = document.createElement("th");
+ th.textContent = label;
+ return th;
+ })
+ );
+ thead.append(tr);
+ return thead;
+ }
+
+ static #tbody(input) {
+ const tbody = document.createElement("tbody");
+
+ const trs = Methods.#methods.map(({ method, params, description }) => {
+ const td1 = document.createElement("td");
+ td1.innerHTML = `${method}`;
+
+ const td2 = document.createElement("td");
+ td2.innerHTML = params
+ ? `myToggle.bootstrapToggle("${params}")`
+ : "myToggle.bootstrapToggle()";
+
+ const td3 = document.createElement("td");
+ td3.textContent = description;
+
+ const td4 = document.createElement("td");
+ const button = document.createElement("button");
+ button.className = "btn btn-outline-dark btn-sm w-100";
+ button.textContent = method;
+ button.onclick = () => {
+ input.bootstrapToggle(params);
+ };
+ td4.append(button);
+
+ const tr = document.createElement("tr");
+ tr.append(td1, td2, td3, td4);
+ return tr;
+ });
+
+ tbody.append(...trs);
+ return tbody;
+ }
+
+ static #asyncAlert() {
+ return ({
+ type: "warning",
+ title: "Async teardown",
+ versionPill: { version: "5.5.0", action: "SINCE" },
+ content: `destroy() and rerender() return Promise<void>. Await before re-initializing or inspecting DOM:
await element.bsToggle.destroy();
+element.bootstrapToggle();
+rerender() emits toggle:disposed and toggle:attached around the re-attach.
on and off user options is deprecated and will throw a console warning. Use onlabel and offlabel user options instead.`,
- },
- });
- }
+ static build() {
+ return super.build({
+ title: "Options",
+ description: Options.#description(),
+ example: Options.#example(),
+ codePanel: Options.#codePanel(),
+ alert: {
+ type: "warning",
+ title: "Deprecation notice",
+ versionPill: {
+ version: "5.0.0",
+ action: "DEPRECATED",
+ },
+ content: "Using on and off user options is deprecated and will throw a console warning. Use onlabel and offlabel user options instead.",
+ },
+ });
+ }
- static #codePanel() {
- const ecmas = `
@@ -47,7 +47,7 @@ class Options extends DocArticle {
});
};
`;
- const jquery = `
@@ -74,59 +74,59 @@ class Options extends DocArticle {
});
});
`;
- return {
- name: "api-options",
- language: "javascript",
- tabs: ["ECMAScript", "jQuery"],
- contents: [ecmas, jquery],
- };
- }
+ return {
+ name: "api-options",
+ language: "javascript",
+ tabs: ["ECMAScript", "jQuery"],
+ contents: [ecmas, jquery],
+ };
+ }
- static #example() {
- const form = document.createElement("form");
- form.id = "form_state_status";
- form.className = "d-flex justify-content-between align-items-center";
+ static #example() {
+ const form = document.createElement("form");
+ form.id = "form_state_status";
+ form.className = "d-flex justify-content-between align-items-center";
- const input = document.createElement("input");
- input.id = "api-option-toggle";
- input.type = "checkbox";
- input.checked = true;
+ const input = document.createElement("input");
+ input.id = "api-option-toggle";
+ input.type = "checkbox";
+ input.checked = true;
- const button = document.createElement("button");
- button.type = "submit";
- button.className = "btn btn-outline-secondary";
- button.innerHTML = "Launch Bootstrap Toggle";
+ const button = document.createElement("button");
+ button.type = "submit";
+ button.className = "btn btn-outline-secondary";
+ button.innerHTML = "Launch Bootstrap Toggle";
- form.append(input, button);
+ form.append(input, button);
- form.onsubmit = (e) => {
- e.preventDefault();
- input.bootstrapToggle({
- onlable: "Enabled",
- offlabel: "Disabled",
- onstyle: "success",
- offstyle: "danger",
- onvalue: "1",
- offvalue: "0",
- size: "lg",
- style: null,
- width: null,
- height: null,
- tabindex: -1,
- tristate: true,
- tooltip: {
- placement: "top",
- title: { on: "Enabled", off: "Disabled", mixed: "Mixed" },
- },
- });
- };
+ form.onsubmit = (e) => {
+ e.preventDefault();
+ input.bootstrapToggle({
+ onlable: "Enabled",
+ offlabel: "Disabled",
+ onstyle: "success",
+ offstyle: "danger",
+ onvalue: "1",
+ offvalue: "0",
+ size: "lg",
+ style: null,
+ width: null,
+ height: null,
+ tabindex: -1,
+ tristate: true,
+ tooltip: {
+ placement: "top",
+ title: { on: "Enabled", off: "Disabled", mixed: "Mixed" },
+ },
+ });
+ };
- return [form];
- }
+ return [form];
+ }
- static #description() {
- const description = document.createElement("div");
- description.innerHTML = `Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-, as in data-on="Enabled". Data attributes will take precedence over JavaScript options.
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-, as in data-on="Enabled". Data attributes will take precedence over JavaScript options.
rerender method. This can be used to update toggle when a process updates input data attributes.`;
-
- const code = `
@@ -21,41 +21,41 @@ class Rerender extends DocArticle {
};
`;
- return super.build({
- title: "Re-render",
- description,
- example: Rerender.#example(),
- codeBlock: {
- language: "html",
- code,
- },
- });
- }
-
- static #example() {
- const form = document.createElement("form");
- form.id = "api-state-form";
- form.className = "d-flex justify-content-between align-items-center";
- form.innerHTML = `
- `;
-
- const console = new Console();
-
- form.onsubmit = (e) => {
- e.preventDefault();
- const myToggle = e.target.elements["api-rerender-toggle"];
- const onLabel = crypto.getRandomValues(new Uint32Array(1))[0];
- myToggle.dataset.onlabel = onLabel;
- console.log({
- mode: "append",
- data: `On label set to: ${onLabel}`,
- });
-
- myToggle.bootstrapToggle("rerender");
- };
-
- return [form, console.htmlElement];
- }
+ return super.build({
+ title: "Re-render",
+ description,
+ example: Rerender.#example(),
+ codeBlock: {
+ language: "html",
+ code,
+ },
+ });
+ }
+
+ static #example() {
+ const form = document.createElement("form");
+ form.id = "api-state-form";
+ form.className = "d-flex justify-content-between align-items-center";
+ form.innerHTML = `
+ `;
+
+ const console = new Console();
+
+ form.onsubmit = (e) => {
+ e.preventDefault();
+ const myToggle = e.target.elements["api-rerender-toggle"];
+ const onLabel = crypto.getRandomValues(new Uint32Array(1))[0];
+ myToggle.dataset.onlabel = onLabel;
+ console.log({
+ mode: "append",
+ data: `On label set to: ${onLabel}`,
+ });
+
+ myToggle.bootstrapToggle("rerender");
+ };
+
+ return [form, console.htmlElement];
+ }
}
export default Rerender;
diff --git a/docs/src/js/components/documentation/api/State.js b/docs/src/js/components/documentation/api/State.js
index 31ad0c5c..5086c57d 100644
--- a/docs/src/js/components/documentation/api/State.js
+++ b/docs/src/js/components/documentation/api/State.js
@@ -2,46 +2,46 @@ import Console from "../../Console";
import DocArticle from "../DocArticle";
class State extends DocArticle {
- static build() {
- const description = document.createElement("p");
- description.innerHTML = `Checked state of a toggle can be set by reading checked property. Use the element property for checked state myToggle.checked (returns true or false).`;
+ static build() {
+ const description = document.createElement("p");
+ description.innerHTML = "Checked state of a toggle can be set by reading checked property. Use the element property for checked state myToggle.checked (returns true or false).";
- const code = `
`;
- return super.build({
- title: "Toggle State",
- description,
- example: State.#example(),
- codeBlock: {
- language: "html",
- code,
- },
- });
- }
-
- static #example() {
- const form = document.createElement("form");
- form.id = "api-state-form";
- form.className = "d-flex justify-content-between align-items-center";
- form.innerHTML = `
+ return super.build({
+ title: "Toggle State",
+ description,
+ example: State.#example(),
+ codeBlock: {
+ language: "html",
+ code,
+ },
+ });
+ }
+
+ static #example() {
+ const form = document.createElement("form");
+ form.id = "api-state-form";
+ form.className = "d-flex justify-content-between align-items-center";
+ form.innerHTML = `
`;
- const console = new Console();
+ const console = new Console();
- form.onsubmit = (e) => {
- e.preventDefault();
- console.log({
- mode: "append",
- data: `Checked: ${e.target.elements["api-state-toggle"].checked}`,
- });
- };
+ form.onsubmit = (e) => {
+ e.preventDefault();
+ console.log({
+ mode: "append",
+ data: `Checked: ${e.target.elements["api-state-toggle"].checked}`,
+ });
+ };
- return [form, console.htmlElement];
- }
+ return [form, console.htmlElement];
+ }
}
export default State;
diff --git a/docs/src/js/components/documentation/devtools/Monitoring.js b/docs/src/js/components/documentation/devtools/Monitoring.js
new file mode 100644
index 00000000..2dd33eba
--- /dev/null
+++ b/docs/src/js/components/documentation/devtools/Monitoring.js
@@ -0,0 +1,185 @@
+import Console from "../../Console";
+import DocArticle from "../DocArticle";
+
+class Monitoring extends DocArticle {
+ /**
+ * Live example state. Only one instance of the demo is created per page
+ * load, so a module-level singleton for the console and the patched
+ * console.debug is acceptable.
+ */
+ static #consoleInstance = null;
+ static #originalDebug = null;
+ static #debugPatched = false;
+
+ static build() {
+ return super.build({
+ title: "Monitoring",
+ description: Monitoring.#description(),
+ versionPill: { action: "SINCE", version: "5.5.0" },
+ });
+ }
+
+ static #description() {
+ const description = document.createElement("div");
+
+ const p1 = document.createElement("p");
+ p1.innerHTML = "Bootstrap5-Toggle is built on component-lifecycle. A Monitor singleton is exposed at window.BootstrapToggle.MONITOR and starts stopped (no listeners attached). Enable it from the browser console:";
+ description.appendChild(p1);
+
+ const code = document.createElement("pre");
+ code.innerHTML = `window.BootstrapToggle.MONITOR.start("DEBUG"); // full tracing
+window.BootstrapToggle.MONITOR.setLevel("INFO"); // lifecycle only
+window.BootstrapToggle.MONITOR.stop(); // silence
+window.BootstrapToggle.MONITOR.getLevel(); // "DEBUG" | "INFO" | "WARN" | "ERROR" | undefined`;
+ description.appendChild(code);
+
+ const p2 = document.createElement("p");
+ p2.innerHTML = "The Toggle component itself is unchanged. MONITOR visibility relies on Toggle being constructed with { bubbleEvents: true }, which is the current default and is not configurable via the public API.";
+ description.appendChild(p2);
+
+ description.appendChild(Monitoring.#logLevelTable());
+ description.appendChild(Monitoring.#liveExample());
+
+ return description;
+ }
+
+ static #liveExample() {
+ const frag = document.createDocumentFragment();
+
+ const title = document.createElement("h4");
+ title.textContent = "Live example";
+ title.className = "text-secondary";
+ frag.appendChild(title);
+
+ const p = document.createElement("p");
+ p.innerHTML = "The buttons below control the actual global window.BootstrapToggle.MONITOR singleton. Log output is mirrored to the panel and also appears in the browser devtools console. Click stop() to restore the global console.";
+ frag.appendChild(p);
+
+ const mockConsole = new Console();
+ Monitoring.#consoleInstance = mockConsole;
+ const buttons = [
+ {
+ label: 'start("DEBUG")',
+ action: () => {
+ Monitoring.#patchConsoleDebug();
+ window.BootstrapToggle.MONITOR.start("DEBUG");
+ mockConsole.log({
+ mode: "append",
+ data: `MONITOR.start("DEBUG") → getLevel(): ${window.BootstrapToggle.MONITOR.getLevel()}`,
+ });
+ },
+ },
+ {
+ label: 'setLevel("INFO")',
+ action: () => {
+ Monitoring.#patchConsoleDebug();
+ window.BootstrapToggle.MONITOR.setLevel("INFO");
+ mockConsole.log({
+ mode: "append",
+ data: `MONITOR.setLevel("INFO") → getLevel(): ${window.BootstrapToggle.MONITOR.getLevel()}`,
+ });
+ },
+ },
+ {
+ label: "stop()",
+ action: () => {
+ try {
+ window.BootstrapToggle.MONITOR.stop();
+ } catch {
+ // ignore: already stopped
+ }
+ Monitoring.#restoreConsoleDebug();
+ mockConsole.log({
+ mode: "append",
+ data: `MONITOR.stop() → getLevel(): ${window.BootstrapToggle.MONITOR.getLevel()}`,
+ });
+ },
+ },
+ ];
+
+ const controls = document.createElement("div");
+ controls.className = "d-flex flex-wrap gap-2 mb-2";
+ buttons.forEach(({ label, action }) => {
+ const btn = document.createElement("button");
+ btn.type = "button";
+ btn.className = "btn btn-outline-secondary btn-sm";
+ btn.textContent = label;
+ btn.addEventListener("click", action);
+ controls.appendChild(btn);
+ });
+ frag.appendChild(controls);
+
+ frag.appendChild(mockConsole.htmlElement);
+ return frag;
+ }
+
+ static #logLevelTable() {
+ const frag = document.createDocumentFragment();
+
+ const title = document.createElement("h4");
+ title.textContent = "Log-level behavior";
+ title.className = "text-secondary";
+ frag.appendChild(title);
+
+ const description = document.createElement("div");
+ description.innerHTML = `
+| Level | +Lifecycle events ( initialized, attached, disposed, destroyed) |
+ Domain events ( on, off, mixed, enabled, disabled, readonly) |
+ Transition events ( transition-cancelled, transition-invalid) |
+
|---|---|---|---|
DEBUG | ✔ | ✔ | ✔ |
INFO | ✘ | ✘ | ✔ |
WARN | ✘ | ✘ | ✔ |
ERROR | ✘ | ✘ | ✘ |
Component base class exposes a chainable typed event API that coexists with the standard DOM element.addEventListener pattern. Both styles receive the same CustomEvent, and both see the same e.detail.state payload on domain events.";
+ description.append(p1);
+
+ const p2 = document.createElement("p");
+ p2.innerHTML =
+ ".on(name, handler) subscribes for every occurrence; .once(name, handler) auto-unsubscribes after the first dispatch; .off(name, handler) removes a specific handler. All three return the component instance, so calls can be chained.";
+ description.append(p2);
+
+ const p3 = document.createElement("p");
+ p3.innerHTML =
+ "Domain events — toggle:on, toggle:off, toggle:mixed, toggle:enabled, toggle:disabled, toggle:readonly — carry a { state: { value, checked, status, indeterminate } } detail payload. Lifecycle events (see the previous article) carry no toggle-state payload.";
+ description.append(p3);
+
+ return description;
+ }
+}
+
+export default ChainableSubscription;
diff --git a/docs/src/js/components/documentation/events/CustomEvents.js b/docs/src/js/components/documentation/events/CustomEvents.js
index 373361b0..724d0899 100644
--- a/docs/src/js/components/documentation/events/CustomEvents.js
+++ b/docs/src/js/components/documentation/events/CustomEvents.js
@@ -3,134 +3,141 @@ import Console from "../../Console";
import DocArticle from "../DocArticle";
class CustomEvents extends DocArticle {
- static #events = [
- {
- name: "toggle:on",
- action: "on",
- },
- {
- name: "toggle:off",
- action: "off",
- },
- {
- name: "toggle:mixed",
- action: "indeterminate",
- },
- {
- name: "toggle:enabled",
- action: "enable",
- },
- {
- name: "toggle:disabled",
- action: "disable",
- },
- {
- name: "toggle:readonly",
- action: "readonly",
- },
- ];
-
- static build() {
- const input = document.createElement("input");
- input.setAttribute("type", "checkbox");
- input.setAttribute("id", "custom-events-toggle");
- input.setAttribute("checked", "");
- input.setAttribute("tristate", "");
- input.setAttribute("data-toggle", "toggle");
- const console = new Console();
-
- CustomEvents.#events.forEach((event) => {
- input.addEventListener(event.name, (e) => {
- console.log({
- mode: "append",
- data: `Event ${event.name} fired. Toggle state: ${JSON.stringify(e.detail.state, null, 2)}`,
+ static #events = [
+ {
+ name: "toggle:on",
+ action: "on",
+ },
+ {
+ name: "toggle:off",
+ action: "off",
+ },
+ {
+ name: "toggle:mixed",
+ action: "indeterminate",
+ },
+ {
+ name: "toggle:enabled",
+ action: "enable",
+ },
+ {
+ name: "toggle:disabled",
+ action: "disable",
+ },
+ {
+ name: "toggle:readonly",
+ action: "readonly",
+ },
+ ];
+
+ static build() {
+ const input = document.createElement("input");
+ input.setAttribute("type", "checkbox");
+ input.setAttribute("id", "custom-events-toggle");
+ input.setAttribute("checked", "");
+ input.setAttribute("tristate", "");
+ input.setAttribute("data-toggle", "toggle");
+ const console = new Console();
+
+ CustomEvents.#events.forEach((event) => {
+ input.addEventListener(event.name, (e) => {
+ const { value, checked, status, indeterminate } = e.detail.state;
+ console.log({
+ mode: "append",
+ data: `Event ${event.name} fired. State: ${JSON.stringify(
+ { value, checked, status, indeterminate },
+ null,
+ 0
+ )}`,
+ });
+ });
});
- });
- });
- return super.build({
- title: "Custom Events",
- description: CustomEvents.#description(input),
- codeBlock: {
- language: "html",
- code: `
+ return super.build({
+ title: "Custom Events",
+ description: CustomEvents.#description(input),
+ codeBlock: {
+ language: "html",
+ code: `
`,
- },
- example: [input, console.htmlElement],
- versionPill: { action: "SINCE", version: "5.3.0" },
- });
- }
-
- static #description(input) {
- const description = document.createElement("div");
-
- const paragraph = document.createElement("p");
- paragraph.innerHTML =
- "Bootstrap Toggle emit custom events when its state or status is changed. The events details contain the current state of the toggle. The following custom events are available:";
- description.append(paragraph, CustomEvents.#table(input));
-
- return description;
- }
-
- static #table(input) {
- const table = document.createElement("table");
- table.className = "table table-striped table-condensed";
- const caption = document.createElement("caption");
- caption.textContent = "Custom events demo";
- table.append(caption, CustomEvents.#thead(), CustomEvents.#tbody(input));
-
- return table;
- }
-
- static #thead() {
- const thead = document.createElement("thead");
- const tr = document.createElement("tr");
- tr.append(
- ...["Event", "Example", "Launch"].map((label) => {
- const th = document.createElement("th");
- th.textContent = label;
- return th;
- }),
- );
- thead.append(tr);
- return thead;
- }
-
- static #tbody(input) {
- const tbody = document.createElement("tbody");
-
- const trs = CustomEvents.#events.map(({ name, action }) => {
- const td1 = document.createElement("td");
- td1.innerHTML = `${name}`;
-
- const td2 = document.createElement("td");
- td2.innerHTML = `myToggle.addEventListener("${name}", (e)=>{...})`;
-
- const td3 = document.createElement("td");
- const defaultBtn = document.createElement("button");
- defaultBtn.className = "btn btn-outline-dark btn-sm w-100";
- defaultBtn.textContent = action;
- defaultBtn.onclick = () => {
- input.bootstrapToggle(action, false);
- };
- td3.append(defaultBtn);
-
- const tr = document.createElement("tr");
- tr.append(td1, td2, td3);
- return tr;
- });
+ },
+ example: [input, console.htmlElement],
+ versionPill: { action: "SINCE", version: "5.3.0" },
+ });
+ }
+
+ static #description(input) {
+ const description = document.createElement("div");
+
+ const paragraph = document.createElement("p");
+ paragraph.innerHTML =
+ "Bootstrap Toggle emit custom events when its state or status is changed. The events details contain the current state of the toggle. The following custom events are available:";
+ description.append(paragraph, CustomEvents.#table(input));
+
+ return description;
+ }
+
+ static #table(input) {
+ const table = document.createElement("table");
+ table.className = "table table-striped table-condensed";
+ const caption = document.createElement("caption");
+ caption.textContent = "Custom events demo";
+ table.append(caption, CustomEvents.#thead(), CustomEvents.#tbody(input));
+
+ return table;
+ }
+
+ static #thead() {
+ const thead = document.createElement("thead");
+ const tr = document.createElement("tr");
+ tr.append(
+ ...["Event", "Example", "Launch"].map((label) => {
+ const th = document.createElement("th");
+ th.textContent = label;
+ return th;
+ }),
+ );
+ thead.append(tr);
+ return thead;
+ }
+
+ static #tbody(input) {
+ const tbody = document.createElement("tbody");
+
+ const trs = CustomEvents.#events.map(({ name, action }) => {
+ const td1 = document.createElement("td");
+ td1.innerHTML = `${name}`;
+
+ const td2 = document.createElement("td");
+ td2.innerHTML = `myToggle.addEventListener("${name}", (e)=>{...})`;
+
+ const td3 = document.createElement("td");
+ const defaultBtn = document.createElement("button");
+ defaultBtn.className = "btn btn-outline-dark btn-sm w-100";
+ defaultBtn.textContent = action;
+ defaultBtn.onclick = () => {
+ input.bootstrapToggle(action, false);
+ };
+ td3.append(defaultBtn);
+
+ const tr = document.createElement("tr");
+ tr.append(td1, td2, td3);
+ return tr;
+ });
- tbody.append(...trs);
- return tbody;
- }
+ tbody.append(...trs);
+ return tbody;
+ }
}
export default CustomEvents;
diff --git a/docs/src/js/components/documentation/events/EventPropagation.js b/docs/src/js/components/documentation/events/EventPropagation.js
index 8f1ead11..26dbda06 100644
--- a/docs/src/js/components/documentation/events/EventPropagation.js
+++ b/docs/src/js/components/documentation/events/EventPropagation.js
@@ -2,12 +2,12 @@ import Console from "../../Console";
import DocArticle from "../DocArticle";
class EventPropagation extends DocArticle {
- static build() {
- const description = document.createElement("p");
- description.innerHTML = `All events are propagated to and from input element to the toggle. Listen for events on the input directly as the toggle stays synced with the
+ static build() {
+ const description = document.createElement("p");
+ description.innerHTML = `All events are propagated to and from input element to the toggle. Listen for events on the input directly as the toggle stays synced with the
input.`;
- const code = `
+ const code = `
`;
- return super.build({
- title: "Event Propagation",
- description,
- example: EventPropagation.#example(),
- codeBlock: {
- language: "html",
- code,
- },
- });
- }
-
- static #example() {
- const input = document.createElement("input");
- input.type = "checkbox";
- input.dataset.toggle = "toggle";
- input.checked = true;
- input.id = "events-propagation-toggle";
-
- const console = new Console();
-
- input.addEventListener("change", (e) => {
- console.log({
- mode: "append",
- data: `Input change fired. Checked state: ${input.checked}`,
- });
- });
-
- return [input, console.htmlElement];
- }
+ return super.build({
+ title: "Event Propagation",
+ description,
+ example: EventPropagation.#example(),
+ codeBlock: {
+ language: "html",
+ code,
+ },
+ });
+ }
+
+ static #example() {
+ const input = document.createElement("input");
+ input.type = "checkbox";
+ input.dataset.toggle = "toggle";
+ input.checked = true;
+ input.id = "events-propagation-toggle";
+
+ const console = new Console();
+
+ input.addEventListener("change", (e) => {
+ console.log({
+ mode: "append",
+ data: `Input change fired. Checked state: ${input.checked}`,
+ });
+ });
+
+ return [input, console.htmlElement];
+ }
}
export default EventPropagation;
diff --git a/docs/src/js/components/documentation/events/LifecycleEvents.js b/docs/src/js/components/documentation/events/LifecycleEvents.js
new file mode 100644
index 00000000..cfe177f4
--- /dev/null
+++ b/docs/src/js/components/documentation/events/LifecycleEvents.js
@@ -0,0 +1,149 @@
+import Console from "../../Console";
+import DocArticle from "../DocArticle";
+
+class LifecycleEvents extends DocArticle {
+ static #events = [
+ {
+ name: "toggle:initialized",
+ trigger: "Fired after `init()` completes (internal state is ready, DOM not yet built).",
+ },
+ {
+ name: "toggle:attached",
+ trigger: "Fired after `attach()` completes (toggle DOM built, listeners bound).",
+ },
+ {
+ name: "toggle:disposed",
+ trigger: "Fired after `dispose()` completes (DOM torn down, listeners unbound). Also fires as part of `rerender()`.",
+ },
+ {
+ name: "toggle:destroyed",
+ trigger: "Fired after `destroy()` completes (instance detached from the input).",
+ },
+ {
+ name: "toggle:transition-cancelled",
+ trigger: "Fired when a lifecycle transition is cancelled before it completes.",
+ },
+ {
+ name: "toggle:transition-invalid",
+ trigger: "Fired when a lifecycle transition is requested from an invalid source state.",
+ },
+ ];
+
+ static build() {
+ const input = document.createElement("input");
+ input.setAttribute("type", "checkbox");
+ input.setAttribute("id", "lifecycle-events-toggle");
+ input.setAttribute("checked", "");
+ input.dataset.toggle = "toggle";
+ const mockConsole = new Console();
+
+ LifecycleEvents.#events.forEach((event) => {
+ input.addEventListener(event.name, (_e) => {
+ mockConsole.log({
+ mode: "append",
+ data: `Event ${event.name} fired.`,
+ });
+ });
+ });
+
+ const rerenderBtn = document.createElement("button");
+ rerenderBtn.type = "button";
+ rerenderBtn.className = "btn btn-outline-secondary btn-sm";
+ rerenderBtn.textContent = "Trigger rerender()";
+ rerenderBtn.onclick = () => {
+ input.bootstrapToggle("rerender");
+ };
+
+ return super.build({
+ title: "Lifecycle Events",
+ description: LifecycleEvents.#description(),
+ codeBlock: {
+ language: "html",
+ code: `
+`,
+ },
+ example: [input, rerenderBtn, mockConsole.htmlElement],
+ versionPill: { action: "SINCE", version: "5.5.0" },
+ });
+ }
+
+ static #description() {
+ const description = document.createElement("div");
+
+ const paragraph = document.createElement("p");
+ paragraph.innerHTML =
+ "Bootstrap Toggle is built on component-lifecycle. Every lifecycle transition automatically emits a prefixed CustomEvent on the input element. These events carry no toggle-state payload — they signal lifecycle moments — and are emitted with bubbles: true, so you can listen for them with element.addEventListener or with the chainable .on() / .once() API (see the next article).";
+ description.append(paragraph, LifecycleEvents.#table());
+
+ const note = document.createElement("p");
+ note.innerHTML =
+ "Note: toggle:initialized and toggle:attached are emitted during initial wiring and cannot be observed by a listener registered after the page is ready. The demo below only observes toggle:disposed and toggle:attached when you click Trigger rerender().";
+ description.append(note);
+
+ return description;
+ }
+
+ static #table() {
+ const table = document.createElement("table");
+ table.className = "table table-striped table-condensed";
+ const caption = document.createElement("caption");
+ caption.textContent = "Lifecycle events emitted by the toggle";
+ table.append(caption, LifecycleEvents.#thead(), LifecycleEvents.#tbody());
+ return table;
+ }
+
+ static #thead() {
+ const thead = document.createElement("thead");
+ const tr = document.createElement("tr");
+ tr.append(
+ ...["Event", "Description"].map((label) => {
+ const th = document.createElement("th");
+ th.textContent = label;
+ return th;
+ })
+ );
+ thead.append(tr);
+ return thead;
+ }
+
+ static #tbody() {
+ const tbody = document.createElement("tbody");
+ const trs = LifecycleEvents.#events.map(({ name, trigger }) => {
+ const td1 = document.createElement("td");
+ td1.innerHTML = `${name}`;
+
+ const td2 = document.createElement("td");
+ td2.innerHTML = trigger;
+
+ const tr = document.createElement("tr");
+ tr.append(td1, td2);
+ return tr;
+ });
+ tbody.append(...trs);
+ return tbody;
+ }
+}
+
+export default LifecycleEvents;
diff --git a/docs/src/js/components/documentation/events/SilencedActions.js b/docs/src/js/components/documentation/events/SilencedActions.js
index c1f382f1..af27a66b 100644
--- a/docs/src/js/components/documentation/events/SilencedActions.js
+++ b/docs/src/js/components/documentation/events/SilencedActions.js
@@ -2,124 +2,124 @@ import Console from "../../Console";
import DocArticle from "../DocArticle";
class SilencedActions extends DocArticle {
- static #methods = [
- "on",
- "off",
- "toggle",
- "indeterminate",
- "determinate",
- "enable",
- "disable",
- "readonly",
- ];
-
- static build() {
- const input = document.createElement("input");
- input.setAttribute("type", "checkbox");
- input.setAttribute("id", "events-silence-toggle");
- input.setAttribute("checked", "");
- input.setAttribute("data-toggle", "toggle");
- const console = new Console();
-
- input.addEventListener("change", (e) => {
- console.log({
- mode: "append",
- data: `Input change fired. Checked state: ${input.checked}`,
- });
- });
-
- return super.build({
- title: "Silenced Actions",
- description: SilencedActions.#description(input),
- codeBlock: {
- language: "html",
- code: `
+ static #methods = [
+ "on",
+ "off",
+ "toggle",
+ "indeterminate",
+ "determinate",
+ "enable",
+ "disable",
+ "readonly",
+ ];
+
+ static build() {
+ const input = document.createElement("input");
+ input.setAttribute("type", "checkbox");
+ input.setAttribute("id", "events-silence-toggle");
+ input.setAttribute("checked", "");
+ input.setAttribute("data-toggle", "toggle");
+ const console = new Console();
+
+ input.addEventListener("change", (e) => {
+ console.log({
+ mode: "append",
+ data: `Input change fired. Checked state: ${input.checked}`,
+ });
+ });
+
+ return super.build({
+ title: "Silenced Actions",
+ description: SilencedActions.#description(input),
+ codeBlock: {
+ language: "html",
+ code: `
`,
- },
- example: [input, console.htmlElement],
- });
- }
+ },
+ example: [input, console.htmlElement],
+ });
+ }
- static #description(input) {
- const description = document.createElement("div");
+ static #description(input) {
+ const description = document.createElement("div");
- const paragraph = document.createElement("p");
- paragraph.innerHTML =
+ const paragraph = document.createElement("p");
+ paragraph.innerHTML =
"Methods can be used in silence mode just specifying the second argument to true on the bootstrapToggle call. This is useful to prevent the control from propagating the change event in cases where you want to update the state, but do not want to fire the onChange event. The following methods are available in silence mode in the following way:";
- description.append(paragraph, SilencedActions.#table(input));
-
- return description;
- }
-
- static #table(input) {
- const table = document.createElement("table");
- table.className = "table table-striped table-condensed";
- const caption = document.createElement("caption");
- caption.textContent = "Silenced methods demo";
- table.append(
- caption,
- SilencedActions.#thead(),
- SilencedActions.#tbody(input),
- );
-
- return table;
- }
-
- static #thead() {
- const thead = document.createElement("thead");
- const tr = document.createElement("tr");
- tr.append(
- ...["Method", "Example", "Normal", "Silenced"].map((label) => {
- const th = document.createElement("th");
- th.textContent = label;
- return th;
- }),
- );
- thead.append(tr);
- return thead;
- }
-
- static #tbody(input) {
- const tbody = document.createElement("tbody");
-
- const trs = SilencedActions.#methods.map((method) => {
- const td1 = document.createElement("td");
- td1.innerHTML = `${method}`;
-
- const td2 = document.createElement("td");
- td2.innerHTML = `myToggle.bootstrapToggle("${method}", true)`;
-
- const td3 = document.createElement("td");
- const defaultBtn = document.createElement("button");
- defaultBtn.className = "btn btn-outline-dark btn-sm w-100";
- defaultBtn.textContent = method;
- defaultBtn.onclick = () => {
- input.bootstrapToggle(method, false);
- };
- td3.append(defaultBtn);
-
- const td4 = document.createElement("td");
- const silenceBtn = document.createElement("button");
- silenceBtn.className = "btn btn-outline-dark btn-sm w-100";
- silenceBtn.textContent = method;
- silenceBtn.onclick = () => {
- input.bootstrapToggle(method, true);
- };
- td4.append(silenceBtn);
-
- const tr = document.createElement("tr");
- tr.append(td1, td2, td3, td4);
- return tr;
- });
-
- tbody.append(...trs);
- return tbody;
- }
+ description.append(paragraph, SilencedActions.#table(input));
+
+ return description;
+ }
+
+ static #table(input) {
+ const table = document.createElement("table");
+ table.className = "table table-striped table-condensed";
+ const caption = document.createElement("caption");
+ caption.textContent = "Silenced methods demo";
+ table.append(
+ caption,
+ SilencedActions.#thead(),
+ SilencedActions.#tbody(input),
+ );
+
+ return table;
+ }
+
+ static #thead() {
+ const thead = document.createElement("thead");
+ const tr = document.createElement("tr");
+ tr.append(
+ ...["Method", "Example", "Normal", "Silenced"].map((label) => {
+ const th = document.createElement("th");
+ th.textContent = label;
+ return th;
+ }),
+ );
+ thead.append(tr);
+ return thead;
+ }
+
+ static #tbody(input) {
+ const tbody = document.createElement("tbody");
+
+ const trs = SilencedActions.#methods.map((method) => {
+ const td1 = document.createElement("td");
+ td1.innerHTML = `${method}`;
+
+ const td2 = document.createElement("td");
+ td2.innerHTML = `myToggle.bootstrapToggle("${method}", true)`;
+
+ const td3 = document.createElement("td");
+ const defaultBtn = document.createElement("button");
+ defaultBtn.className = "btn btn-outline-dark btn-sm w-100";
+ defaultBtn.textContent = method;
+ defaultBtn.onclick = () => {
+ input.bootstrapToggle(method, false);
+ };
+ td3.append(defaultBtn);
+
+ const td4 = document.createElement("td");
+ const silenceBtn = document.createElement("button");
+ silenceBtn.className = "btn btn-outline-dark btn-sm w-100";
+ silenceBtn.textContent = method;
+ silenceBtn.onclick = () => {
+ input.bootstrapToggle(method, true);
+ };
+ td4.append(silenceBtn);
+
+ const tr = document.createElement("tr");
+ tr.append(td1, td2, td3, td4);
+ return tr;
+ });
+
+ tbody.append(...trs);
+ return tbody;
+ }
}
export default SilencedActions;
diff --git a/docs/src/js/components/documentation/features/AnimationSpeed.js b/docs/src/js/components/documentation/features/AnimationSpeed.js
index fe2c1e70..4d516768 100644
--- a/docs/src/js/components/documentation/features/AnimationSpeed.js
+++ b/docs/src/js/components/documentation/features/AnimationSpeed.js
@@ -1,11 +1,11 @@
import DocArticle from "../DocArticle";
class AnimationSpeed {
- static build() {
- const description = document.createElement("p");
- description.innerHTML = `Transition speed can be easily controlled with css transition property on .toggle-group. You can also turn animation off completely.`;
+ static build() {
+ const description = document.createElement("p");
+ description.innerHTML = "Transition speed can be easily controlled with css transition property on .toggle-group. You can also turn animation off completely.";
- const code = `
`;
- return DocArticle.build({
- title: "Custom Style",
- description,
- example: CustomStyle.#example(),
- codeBlock: {
- language: "html",
- code,
- },
- });
- }
-
- static #example() {
- const iosStyle = document.createElement("style");
- iosStyle.textContent = `.toggle.ios, .toggle.ios .toggle-on, .toggle.ios .toggle-off, .toggle.ios .toggle-handle { border-radius: 20rem; }`;
-
- const iosInput = document.createElement("input");
- iosInput.type = "checkbox";
- iosInput.checked = true;
- iosInput.dataset.toggle = "toggle";
- iosInput.dataset.style = "ios";
-
- const androidStyle = document.createElement("style");
- androidStyle.textContent = `.toggle.android , .toggle.android .toggle-on, .toggle.android .toggle-off, .toggle.android .toggle-handle{ border-radius: 0px; }`;
-
- const androidInput = document.createElement("input");
- androidInput.type = "checkbox";
- androidInput.checked = true;
- androidInput.dataset.toggle = "toggle";
- androidInput.dataset.style = "android";
-
- return [iosStyle, iosInput, androidStyle, androidInput];
- }
+ return DocArticle.build({
+ title: "Custom Style",
+ description,
+ example: CustomStyle.#example(),
+ codeBlock: {
+ language: "html",
+ code,
+ },
+ });
+ }
+
+ static #example() {
+ const iosStyle = document.createElement("style");
+ iosStyle.textContent = ".toggle.ios, .toggle.ios .toggle-on, .toggle.ios .toggle-off, .toggle.ios .toggle-handle { border-radius: 20rem; }";
+
+ const iosInput = document.createElement("input");
+ iosInput.type = "checkbox";
+ iosInput.checked = true;
+ iosInput.dataset.toggle = "toggle";
+ iosInput.dataset.style = "ios";
+
+ const androidStyle = document.createElement("style");
+ androidStyle.textContent = ".toggle.android , .toggle.android .toggle-on, .toggle.android .toggle-off, .toggle.android .toggle-handle{ border-radius: 0px; }";
+
+ const androidInput = document.createElement("input");
+ androidInput.type = "checkbox";
+ androidInput.checked = true;
+ androidInput.dataset.toggle = "toggle";
+ androidInput.dataset.style = "android";
+
+ return [iosStyle, iosInput, androidStyle, androidInput];
+ }
}
export default CustomStyle;
diff --git a/docs/src/js/components/documentation/features/CustomText.js b/docs/src/js/components/documentation/features/CustomText.js
index 5ea4f21b..8769c2d8 100644
--- a/docs/src/js/components/documentation/features/CustomText.js
+++ b/docs/src/js/components/documentation/features/CustomText.js
@@ -1,51 +1,51 @@
import DocArticle from "../DocArticle";
class CustomText {
- static build() {
- const description = document.createElement("p");
- description.innerHTML = `Bootstrap toggle allows to set custom labels. Just add the data-onlabel or data-offlabel attribute to set a custom label. Plain text and HTML are supported.`;
+ static build() {
+ const description = document.createElement("p");
+ description.innerHTML = "Bootstrap toggle allows to set custom labels. Just add the data-onlabel or data-offlabel attribute to set a custom label. Plain text and HTML are supported.";
- const code = `
+ const code = `
`;
- return DocArticle.build({
- title: "Custom Text",
- description,
- example: CustomText.#example(),
- codeBlock: {
- language: "html",
- code,
- },
- alert: {
- type: "warning",
- title: "Deprecation notice",
- versionPill: {
- version: "5.0.0",
- action: "DEPRECATED",
- },
- content: `Using data-on and data-off data attributes is deprecated and will throw a console warning. Use data-onlabel and data-offlabel data attributes instead.`,
- },
- });
- }
+ return DocArticle.build({
+ title: "Custom Text",
+ description,
+ example: CustomText.#example(),
+ codeBlock: {
+ language: "html",
+ code,
+ },
+ alert: {
+ type: "warning",
+ title: "Deprecation notice",
+ versionPill: {
+ version: "5.0.0",
+ action: "DEPRECATED",
+ },
+ content: "Using data-on and data-off data attributes is deprecated and will throw a console warning. Use data-onlabel and data-offlabel data attributes instead.",
+ },
+ });
+ }
- static #example() {
- const input1 = document.createElement("input");
- input1.type = "checkbox";
- input1.checked = true;
- input1.dataset.toggle = "toggle";
- input1.dataset.onlabel = "Ready";
- input1.dataset.offlabel = "Not Ready";
- input1.dataset.onstyle = "success";
- input1.dataset.offstyle = "danger";
+ static #example() {
+ const input1 = document.createElement("input");
+ input1.type = "checkbox";
+ input1.checked = true;
+ input1.dataset.toggle = "toggle";
+ input1.dataset.onlabel = "Ready";
+ input1.dataset.offlabel = "Not Ready";
+ input1.dataset.onstyle = "success";
+ input1.dataset.offstyle = "danger";
- const input2 = document.createElement("input");
- input2.type = "checkbox";
- input2.checked = true;
- input2.dataset.toggle = "toggle";
- input2.dataset.onlabel = " Play";
- input2.dataset.offlabel = " Pause";
+ const input2 = document.createElement("input");
+ input2.type = "checkbox";
+ input2.checked = true;
+ input2.dataset.toggle = "toggle";
+ input2.dataset.onlabel = " Play";
+ input2.dataset.offlabel = " Pause";
- return [input1, input2];
- }
+ return [input1, input2];
+ }
}
export default CustomText;
diff --git a/docs/src/js/components/documentation/features/CustomTitle.js b/docs/src/js/components/documentation/features/CustomTitle.js
index 9728616a..555cde72 100644
--- a/docs/src/js/components/documentation/features/CustomTitle.js
+++ b/docs/src/js/components/documentation/features/CustomTitle.js
@@ -1,44 +1,44 @@
import DocArticle from "../DocArticle";
class CustomTitle {
- static build() {
- const description = document.createElement("p");
- description.innerHTML = `Bootstrap toggle allows to set custom title. Just add the data-ontitle or data-offtitle attribute to set a custom label. To set the same title in
+ static build() {
+ const description = document.createElement("p");
+ description.innerHTML = `Bootstrap toggle allows to set custom title. Just add the data-ontitle or data-offtitle attribute to set a custom label. To set the same title in
both parts just use HTML standard title attribute.`;
- const code = `
+ const code = `
`;
- return DocArticle.build({
- title: "Custom Title",
- description,
- versionPill: {
- version: "5.0.0",
- action: "SINCE",
- },
- example: CustomTitle.#example(),
- codeBlock: {
- language: "html",
- code,
- },
- });
- }
+ return DocArticle.build({
+ title: "Custom Title",
+ description,
+ versionPill: {
+ version: "5.0.0",
+ action: "SINCE",
+ },
+ example: CustomTitle.#example(),
+ codeBlock: {
+ language: "html",
+ code,
+ },
+ });
+ }
- static #example() {
- const input1 = document.createElement("input");
- input1.type = "checkbox";
- input1.checked = true;
- input1.dataset.toggle = "toggle";
- input1.dataset.ontitle = "ON";
- input1.dataset.offtitle = "OFF";
+ static #example() {
+ const input1 = document.createElement("input");
+ input1.type = "checkbox";
+ input1.checked = true;
+ input1.dataset.toggle = "toggle";
+ input1.dataset.ontitle = "ON";
+ input1.dataset.offtitle = "OFF";
- const input2 = document.createElement("input");
- input2.type = "checkbox";
- input2.checked = true;
- input2.dataset.toggle = "toggle";
- input2.title = "TOGGLE";
+ const input2 = document.createElement("input");
+ input2.type = "checkbox";
+ input2.checked = true;
+ input2.dataset.toggle = "toggle";
+ input2.title = "TOGGLE";
- return [input1, input2];
- }
+ return [input1, input2];
+ }
}
export default CustomTitle;
diff --git a/docs/src/js/components/documentation/features/FormLayout.js b/docs/src/js/components/documentation/features/FormLayout.js
index 0633c843..17fbac8c 100644
--- a/docs/src/js/components/documentation/features/FormLayout.js
+++ b/docs/src/js/components/documentation/features/FormLayout.js
@@ -2,11 +2,11 @@ import Console from "../../Console";
import DocArticle from "../DocArticle";
class FormLayout {
- static build() {
- const description = document.createElement("p");
- description.innerHTML = `Bootstrap toggle can be used in all bootstrap form layout.`;
+ static build() {
+ const description = document.createElement("p");
+ description.innerHTML = "Bootstrap toggle can be used in all bootstrap form layout.";
- const code = `
+ const code = `