diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 49be26530..7ac33d315 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -45,6 +45,14 @@ Please carefully read the contribution docs before creating a pull request -- [ ] I have linked an issue or discussion. -- [ ] I have updated the documentation accordingly. -- [ ] I have documented testing approach + + + + + +- [ ] I have verified accessibility of any new components by: + - [ ] automated check with the WAVE browser extension + - [ ] navigating by keyboard + - [ ] using with a screen reader (e.g. VoiceOver on Safari) +- [ ] I have included any Storyblok component schema updates. +- [ ] I have updated any applicable documentation. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d660cea33..01137e7fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,45 +9,40 @@ on: branches: - main - master + - esds-3.0-vue3-primevue jobs: ci: - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: [ubuntu-latest] - node: [16] + runs-on: ubuntu-latest steps: - name: Checkout ๐Ÿ›Ž - uses: actions/checkout@master + uses: actions/checkout@v4 + + - name: Get nodenv version ๐Ÿ”Œ + id: nodenv + shell: bash + run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT - name: Setup node env ๐Ÿ— - uses: actions/setup-node@v3.7.0 + uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node }} + node-version: '${{ steps.nodenv.outputs.node-version }}' check-latest: true - - name: Cache node_modules ๐Ÿ“ฆ - uses: actions/cache@v3.3.1 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-node- - - name: Install dependencies ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป run: | make install - make update-peer-deps - make build-scss-pkg - make symlink - make build-vue-pkg make symlink + - name: Building + run: make build + - name: Run linter ๐Ÿ‘€ run: make lint + - name: Run typechecker + run: make typecheck + - name: Run tests ๐Ÿงช run: make test diff --git a/.github/workflows/deploy-v3.yml b/.github/workflows/deploy-v3.yml new file mode 100644 index 000000000..8151b8514 --- /dev/null +++ b/.github/workflows/deploy-v3.yml @@ -0,0 +1,60 @@ +name: build & deploy esds 3.0 + +on: + push: + branches: + - esds-3.0-vue3-primevue + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + + steps: + - name: Checkout Repo ๐Ÿ—ƒ๏ธ + uses: actions/checkout@v4 + with: + ref: esds-3.0-vue3-primevue + + - name: Log into ES_DS_DEV AWS account ๐Ÿ”‘ + id: creds + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-east-1 + role-to-assume: arn:aws:iam::453321834875:role/github-write-to-s3 + output-credentials: true + + - name: Log into CodeArtifact ๐Ÿ—๏ธ + shell: bash + run: | + aws codeartifact login --tool npm --domain energysage --domain-owner 659694780082 --repository cloud-engineering + + - name: Get nodenv version ๐Ÿ”Œ + id: nodenv + shell: bash + run: echo "node-version=$(cat .node-version)" >> $GITHUB_OUTPUT + + - name: Setup node env ๐Ÿ— + uses: actions/setup-node@v4 + with: + node-version: '${{ steps.nodenv.outputs.node-version }}' + check-latest: true + + - name: Install dependencies ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป + run: | + make install + make symlink + + - name: Build ES-DS Version 3 ๐Ÿ› ๏ธ + working-directory: ./es-ds-docs + shell: bash + run: | + npm run generate + + - name: Deploy to S3 ๐Ÿ“ + working-directory: ./es-ds-docs + shell: bash + run: | + aws s3 cp --recursive .output/public/ s3://es-ds-version-2 diff --git a/.gitignore b/.gitignore index 5ce085587..694d5e8af 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ dist stats coverage cdk.out +.nuxt +.output # vscode .vscode/* diff --git a/.node-version b/.node-version index 3c5535cf6..3516580bb 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -18.19.1 +20.17.0 diff --git a/.vscode/extensions.json b/.vscode/extensions.json index bea940b88..1d41984f3 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,16 +2,11 @@ "recommendations": [ "davidanson.vscode-markdownlint", "stylelint.vscode-stylelint", - "redhat.vscode-yaml", - "octref.vetur", + "lokalise.i18n-ally", + "EditorConfig.EditorConfig", "dbaeumer.vscode-eslint", - "editorconfig.editorconfig", - "mikestead.dotenv", "esbenp.prettier-vscode", - "lokalise.i18n-ally", - "zignd.html-css-class-completion", - "christian-kohler.path-intellisense", - "simonsiefke.svg-preview", - "wayou.vscode-todo-highlight" + "Vue.volar", + "redhat.vscode-yaml" ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c482077c..bfa06a07f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -426,7 +426,7 @@ the new `showPrivacySection` prop - Truncated display name - Emit the file name as payload for emitted events - Added a `humanReadable` field to the `mime-type-finder` utils to support better error handling -- The internal `DsResponsiveTable` component used to generate slots and props documentation on the `Typography`,`EsCard`, `EsFileInput`, `EsFileThumbnail`, and `EsSupportCard` pages now has the ability to customize its column widths to match the layout grid in the same manner as `` by taking breakpoint props for `md` and up +- The internal `DsResponsiveTable` component used to generate slots and props documentation on the `Typography`,`EsCard`, `EsFileInput`, `EsFileThumbnail`, and `EsSupportCard` pages now has the ability to customize its column widths to match the layout grid in the same manner as `` by taking breakpoint props for `md` and up ## [0.23.2] - 2023-07-13 diff --git a/Makefile b/Makefile index aeadc2001..5d5fa0032 100644 --- a/Makefile +++ b/Makefile @@ -1,50 +1,63 @@ +# Run local v3 docs site with hot reloading hooked up to es-ds-styles and es-ds-components + .PHONY: dev -dev: - overmind s +dev: symlink + cd es-ds-docs; npm run dev + +.PHONY: symlink +symlink: + cd es-ds-styles; npm link + cd es-ds-components; npm link + cd es-ds-docs; npm link @energysage/es-ds-styles @energysage/es-ds-components + +# Unlink local v3 docs site from local es-ds-styles and es-ds-components; restore to NPM versions + +.PHONY: unlink +unlink: + cd es-ds-styles; npm unlink @energysage/es-ds-styles + cd es-ds-components; npm unlink @energysage/es-ds-components + cd es-ds-docs; npm unlink --no-save @energysage/es-ds-styles + cd es-ds-docs; npm unlink --no-save @energysage/es-ds-components + cd es-ds-docs npm install .PHONY: lint lint: - npx lerna run lint + npm --prefix es-ds-styles run lint || { echo "Linting failed. Forgot to run 'make format'?"; exit 1; } + npm --prefix es-ds-components run lint || { echo "Linting failed. Forgot to run 'make format'?"; exit 1; } + npm --prefix es-ds-docs run lint || { echo "Linting failed. Forgot to run 'make format'?"; exit 1; } + +.PHONY: format +format: + npm --prefix es-ds-components run format + npm --prefix es-ds-docs run format .PHONY: test test: - npx lerna run test + npm --prefix es-ds-styles run test +# TODO: set up testing for es-ds-components and es-ds-docs +# npm --prefix es-ds-components run test +# npm --prefix es-ds-docs run test .PHONY: build build: - npx lerna run build + npm --prefix es-ds-styles run build + npm --prefix es-ds-docs run build +# es-ds-components does not have a build step -.PHONY: publish -publish: - npx lerna publish - -.PHONY: symlink -symlink: - npx lerna bootstrap - -.PHONE: reload -reload: - npm --prefix es-vue-base run build - npx lerna bootstrap +.PHONY: typecheck +typecheck: + cd es-ds-docs && npx nuxi typecheck # Sometimes Called .PHONY: install install: - npm install - npx lerna exec -- npm install + npm --prefix es-ds-styles install + npm --prefix es-ds-components install + npm --prefix es-ds-docs install # Bootstraping Commands (not reguarly called) -.PHONY: build-scss-pkg -build-scss-pkg: - npm run --prefix es-bs-base build - -.PHONY: build-vue-pkg -build-vue-pkg: - npm run --prefix es-vue-base build - -.PHONY: update-peer-deps -update-peer-deps: - npm --prefix es-vue-base install bootstrap-vue@2 \ - vue@2 +.PHONY: update-package-deps +update-package-deps: + cd es-ds-docs; npm uninstall @energysage/es-ds-styles && npm install @energysage/es-ds-styles && npm uninstall @energysage/es-ds-components && npm install @energysage/es-ds-components diff --git a/Procfile b/Procfile deleted file mode 100644 index 01cba331e..000000000 --- a/Procfile +++ /dev/null @@ -1,2 +0,0 @@ -es-design-system: npm --prefix es-design-system run dev -watcher: npm run watch diff --git a/README.md b/README.md index 284a2a9e4..8db6e4d0c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ +**NOTICE: this is a vue3 based design system, if you're working with a vue2 and/or bootstrap based micro-frontend, please see [EnergySage/es-ds-legacy](https://github.com/EnergySage/es-ds-legacy) instead** + # EnergySage Design System This is a **monorepo** containing the elements required for building experiences -following the EnergySage Design System of _es-ds_ for short. +following the EnergySage Design System, or _es-ds_ for short. -- [Public Works](#public-works) +- [Public works](#public-works) - [The parts](#the-parts) - [Contributing](#contributing) -## Public Works +## Public works This repository `es-ds` **is public** and the contents are licensed under the [MIT](https://tldrlegal.com/license/mit-license#summary) @@ -20,60 +22,50 @@ within private org channels. For EnergySage specific resources & channels see the [Quick Links section of the Design System confluence page](https://energysage.atlassian.net/wiki/spaces/DS/overview#%F0%9F%96%B1%EF%B8%8F-Quick-Links) -## The Parts +## The parts -The EnergySage Design System is composed of 2 core npm packages: +Starting in version 3.0, the EnergySage Design System is composed of 2 core npm packages: -- [@energysage/es-bs-base](https://www.npmjs.com/package/@energysage/es-bs-base) -- [@energysage/es-vue-base](https://www.npmjs.com/package/@energysage/es-vue-base) +- [@energysage/es-ds-styles](https://www.npmjs.com/package/@energysage/es-ds-styles) +- [@energysage/es-ds-components](https://www.npmjs.com/package/@energysage/es-ds-components) ```mermaid graph TB subgraph es-ds subgraph "@energysage" - A["@energysage/es-bs-base"] - C["@energysage/es-vue-base"] + A["@energysage/es-ds-styles"] + C["@energysage/es-ds-components"] end - D[es-design-system] + D[es-ds-docs] C-->D end - Y(nuxt2) - Z(vue-bootstrap) --> C + Y(nuxt3) + Z(primevue) --> C Y-->D ``` -### es-bs-base - -[es-bs-base](./es-bs-base/) started as a fork **bootstrap 4**. - -This package overrides the `_variables.scss` file in bootstrap to the ones use -defaults required by the energysage design system. - -There's additional variables and colors that diverge and extend from the core -bootstrap framework. +**es-ds-styles** -Additionally the SASS has been refactored to use +- [es-ds-styles](es-ds-styles/) started as a fork of **Bootstrap 4**. +- This package overrides the `_variables.scss` file in Bootstrap to the defaults required by the EnergySage design system. +- There are additional variables and colors that diverge and extend from the core +Bootstrap framework. +- The SASS has also been refactored to use [the modular system](https://sass-lang.com/blog/the-module-system-is-launched/) and dart-sass compiler. +- Prior to v3.0, `es-ds-styles` worked with the `es-vue-base` package, which is based on +[bootstrap-vue](https://bootstrap-vue.org/). As such, there are still some legacy +Bootstrap Vue styles present in `es-ds-styles`. Those are deprecated and will be removed +in a future version. -`es-vue-base` has a peer-dependency of -[bootstrap-vue](https://bootstrap-vue.org/) which is used for vue components. -Associated styling is vendorized in `es-bs-base` and re-written using the SASS -modular system. - -### es-vue-base - -[es-vue-base](./es-vue-base/) contains vue components for use in nuxt projects. -It has a dependency of [bootstrap-vue](https://bootstrap-vue.org/) as components -extends or are composed of bootstrap components. - -`es-bs-base` is a sibling dependencies and should provide the baseline CSS -styling to vue rendered components. +**es-ds-components** +- [es-ds-components](./es-ds-components/) contains Vue 3 components for use in Nuxt 3 projects. +It is primarily based on [PrimeVue](https://primevue.org/), with some customizations specific to EnergySage. -### es-design-system - -This is our design-system documentation branch, and reference integration for -the `es-ds` packages. +**es-ds-docs** +- This is the design system documentation site powered by Nuxt 3. +- It also serves a reference for +how to integrate `es-ds` packages into a Nuxt 3 project. ## Contributing @@ -92,86 +84,40 @@ origin git@github.com:EnergySage/es-ds.git (push) ### Installing Dependencies and Linking packages -1. `make install` - installs all packages from npm -2. `make update-peer-deps` - installs necessary peer deps for `es-vue-base` used - in `es-design-system` -3. `make build-scss-pkg` - build `es-bs-base/dist` locally; we do this first - since `es-vue-base` imports it `@import '~@energysage/es-bs-base/scss/includes'` -4. `make symlink` - [symlink or bootstrap](https://lerna.js.org/docs/features/bootstrap) `es-bs-base/dist` -5. `make build-vue-pkg` - build `es-vue-base/dist` locally -6. `make symlink` - [symlink or bootstrap](https://lerna.js.org/docs/features/bootstrap) - `es-bs-base/dist` and `es-vue-base/dist` for use in `es-design-system` - -### Development Workflow - -To develop with hot reloading for all packages you'll want to run `make dev` in -the `es-ds` directory. This will build and package `es-bs-base` and -`es-vue-base` and symlink them to `es-design-system` for use in the nuxt app. It -will then start a dev instance for `es-design-system` that will be available at -`http://localhost:8500`. - -Hot reloading will take longer than a typical nuxt app, as it will need to -rebuild the packages and re-link them. This is expected. +1. `make install && make symlink` - installs all packages from npm -#### Faster Reloads Hack - -In a terminal run: +### Development workflow ``` -find es-vue-base/src/ | entr -s 'npm --prefix es-vue-base run build' +make dev ``` -(You may need to run `brew install entr` first) +This command will: -In another terminal run: +- Locally link your `es-ds-styles` and `es-ds-components` folders to the `es-ds-docs` Nuxt app +- Start the `es-ds-docs` local dev server +You can then make changes as desired in either upstream package folder and the local dev server should immediately reflect those changes. ``` -(cd es-design-system && FAST_LOCAL=true npm run dev) +make unlink ``` -This will result in much faster reloads that skip rebuilding all of `es-bs-base` -as well as skipping server-side rendering. But *note* this will also throw an -error in webpack-dev server until `es-vue-base` finishes compiling, then it -should recover. - -You must also ensure things work server-side before committing your changes. - -Once we upgrade to Lerna 6, this should all be much faster & smoother via native [Workspace watching](https://lerna.js.org/docs/features/workspace-watching) +This command will: +- Undo the local linking set up by the above command +- Reinstall the public NPM versions of the `es-ds-styles` and `es-ds-components` packages -#### Vue Component Process +This enables you to run the `es-ds-docs` server with the state of code that is publicly available on NPM. -##### Unit Tests - -When adding vue components to [es-vue-base](./es-vue-base/src/lib-components), -it is expected that you also write [unit-tests](./es-vue-base/tests/). - -At a minimum it's recommended you create a snapshot test to catch any potential -regressions in rendered output. Depending on complexity further tests may be -required. - -Tests can be run via `make test`, but this will run tests for all packages in -the repo. For faster feedback, you can `cd es-vue-base` and run `npm run test` -to only run tests for the _es-vue-base_ package. - -##### Building & Re-linking - -Once tests are passing, you'll need to rebuild the _es-vue-base_ package. This -can be done via `npm run build`. - -Next you'll want to move back to the root of the monorepo, and run `make -symlink`. This will ensure the new package is _sym-linked_ to the other projects -in the monorepo. - -### Documenting change - -Once your changes have been made, you'll want to ensure they're documented -somewhere in `es-design-system`. If the change is a new component, it's expected -you'll create a new page to display the component. +``` +cd es-ds-docs +npm run dev +``` -_Note_ This step also functions as a form of integration testing as it will -validate the component will import and render on a nuxt page. +These commands will: +- Run the `es-ds-docs` local dev server without locally linking to the `es-ds-styles` and `es-ds-components` packages folders +- Whichever versions of the two upstream packages are installed (or already locally linked) will be used ### Updating the changelog @@ -197,62 +143,24 @@ in the changelog when publishing a new release. ### Publishing and Versioning -For simplicity of deployment, versioning of packages are fixed and updated -together. - -#### Publishing a new version of a package - Assuming changes are approved, the process of publishing a new version is... - 0. Ensure your local environment is [setup](./README.md#installing-dependencies-and-linking-packages) and you are on the `main` branch -1. `npm login` - Logs you into the npm.js registry. You'll need access to our `es-ds` package there in order for things to work. -2. `make install && make symlink` - Install the new published versions locally - and symlink them -3. `make build` - Build all packages to `*/dist` folders locally -4. `make lint && make test` - Run tests and linting to ensure they pass -5. `make publish` - Publish updated packages to - [npmjs.com](https://www.npmjs.com/org/energysage) -6. Update [CHANGELOG.md](./CHANGELOG.md) with our newly published changes -7. `make install && make symlink` - Install the new published versions locally - and symlink them -8. `git commit -m "docs: :memo: add version X.X.X to the changelog" && git push` - +1. Make sure the package.json versions in `es-ds-styles` and `es-ds-components` is updated to a new version + that hasn't been published before on NPM. +2. `npm login` - Logs you into the npm.js registry. You'll need access to our `es-ds` package there in order for things to work. +3. `make install && make symlink` - Install and symlink dependencies locally +4. `make build` - Build all packages to `*/dist` folders locally +5. `make lint && make typecheck && make test` - Run tests and linting to ensure they pass +6. Publish updated packages to + [npmjs.com](https://www.npmjs.com/org/energysage) with npm publish. + 1. `cd es-ds-styles && npm publish && cd ..` + 2. `cd es-ds-components && npm publish && cd ..` +7. Update [CHANGELOG.md](./CHANGELOG.md) with our newly published changes +8. `make update-package-deps` - Install the new published versions locally +9. `git commit -m "docs: :memo: add version X.X.X to the changelog" && git push` - Commit and push the changelog and `package-lock.json` updates -9. For updating the design-system website see - [Deploy Design System](https://energysage.atlassian.net/wiki/spaces/DSE/pages/208568321/Deploy+Design+System+Documentation) - -Running `make publish` will trigger the following prompt: - -```shell -lerna info Looking for changed packages since v0.1.9 -? Select a new version (currently 0.1.9) -โฏ Patch (0.1.10) - Minor (0.2.0) - Major (1.0.0) - Prepatch (0.1.10-alpha.0) - Preminor (0.2.0-alpha.0) - Premajor (1.0.0-alpha.0) - Custom Prerelease - Custom Version -``` -You'll note the lerna script will walk you through versioning, then push your -changes, and tag the release in git. - -This project follows [semantic versioning](https://semver.org/). Please make -sure your change in version reflects the semantics defined via semver. At a high -level the guidelines are: - -1. MAJOR version changes introduce incompatible API changes. API changes could - mean: - - removal of core-components used in other verticals - - changing "props" of core-components causing breaking changes in other verticals -2. MINOR version changes add functionality in a backwards compatible manner. - This could mean: - - changing the hex value represented by the variable `$white` in - `es-bs-base` - - adding an additional "prop" to a core-component, but otherwise not - chancing the default behavior -3. PATCH version changes are backwards compatible bug-fixes and should have no - impact on functionality aside from fixing a bug +For updating the design-system website see +[Deploy Design System](https://energysage.atlassian.net/wiki/spaces/CE/pages/1094058044/3.0+and+later+Deploy+Design+System+Documentation) diff --git a/es-bs-base/README.md b/es-bs-base/README.md deleted file mode 100644 index 7ae57a1c7..000000000 --- a/es-bs-base/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# EnergySage es-bs-base - -An EnergySage branded Bootstrap - -## Getting Started - -`npm install @energysage/es-bs-base` - -### Basic Example Usage - -main.scss: - -```scss -@import '~@energysage/es-bs-base/scss/bootstrap'; -``` - -test.html: - -```html -

Hello World

-``` diff --git a/es-bs-base/build/build-plugins.js b/es-bs-base/build/build-plugins.js deleted file mode 100644 index 12ed7dcae..000000000 --- a/es-bs-base/build/build-plugins.js +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to build our plugins to use them separately. - * Copyright 2020-2022 The Bootstrap Authors - * Copyright 2020-2022 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const path = require('node:path') -const rollup = require('rollup') -const { babel } = require('@rollup/plugin-babel') -const banner = require('./banner.js') - -const TEST = process.env.NODE_ENV === 'test' -const plugins = [ - babel({ - // Only transpile our source code - exclude: 'node_modules/**', - // Include the helpers in each file, at most one copy of each - babelHelpers: 'bundled' - }) -] -const bsPlugins = { - Alert: path.resolve(__dirname, '../js/src/alert.js'), - Button: path.resolve(__dirname, '../js/src/button.js'), - Carousel: path.resolve(__dirname, '../js/src/carousel.js'), - Collapse: path.resolve(__dirname, '../js/src/collapse.js'), - Dropdown: path.resolve(__dirname, '../js/src/dropdown.js'), - Modal: path.resolve(__dirname, '../js/src/modal.js'), - Popover: path.resolve(__dirname, '../js/src/popover.js'), - ScrollSpy: path.resolve(__dirname, '../js/src/scrollspy.js'), - Tab: path.resolve(__dirname, '../js/src/tab.js'), - Toast: path.resolve(__dirname, '../js/src/toast.js'), - Tooltip: path.resolve(__dirname, '../js/src/tooltip.js'), - Util: path.resolve(__dirname, '../js/src/util.js') -} -const rootPath = TEST ? '../js/coverage/dist/' : '../js/dist/' - -const build = async plugin => { - console.log(`Building ${plugin} plugin...`) - - const external = ['jquery', 'popper.js'] - const globals = { - jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode - 'popper.js': 'Popper' - } - - // Do not bundle Util in plugins - if (plugin !== 'Util') { - external.push(bsPlugins.Util) - globals[bsPlugins.Util] = 'Util' - } - - // Do not bundle Tooltip in Popover - if (plugin === 'Popover') { - external.push(bsPlugins.Tooltip) - globals[bsPlugins.Tooltip] = 'Tooltip' - } - - const pluginFilename = `${plugin.toLowerCase()}.js` - const bundle = await rollup.rollup({ - input: bsPlugins[plugin], - plugins, - external - }) - - await bundle.write({ - banner: banner(), - format: 'umd', - name: plugin, - sourcemap: true, - globals, - file: path.resolve(__dirname, `${rootPath}${pluginFilename}`) - }) - - console.log(`Building ${plugin} plugin... Done!`) -} - -const main = async () => { - try { - await Promise.all(Object.keys(bsPlugins).map(plugin => build(plugin))) - } catch (error) { - console.error(error) - - process.exit(1) - } -} - -// eslint-disable-next-line unicorn/prefer-top-level-await -main() diff --git a/es-bs-base/build/rollup.config.js b/es-bs-base/build/rollup.config.js deleted file mode 100644 index cd378252d..000000000 --- a/es-bs-base/build/rollup.config.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict' - -const path = require('node:path') -const { babel } = require('@rollup/plugin-babel') -const { nodeResolve } = require('@rollup/plugin-node-resolve') -const banner = require('./banner.js') - -const BUNDLE = process.env.BUNDLE === 'true' - -let fileDest = 'bootstrap.js' -const external = ['jquery', 'popper.js'] -const plugins = [ - babel({ - // Only transpile our source code - exclude: 'node_modules/**', - // Include the helpers in the bundle, at most one copy of each - babelHelpers: 'bundled' - }) -] -const globals = { - jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode - 'popper.js': 'Popper' -} - -if (BUNDLE) { - fileDest = 'bootstrap.bundle.js' - // Remove last entry in external array to bundle Popper - external.pop() - delete globals['popper.js'] - plugins.push(nodeResolve()) -} - -module.exports = { - input: path.resolve(__dirname, '../js/index.js'), - output: { - banner, - file: path.resolve(__dirname, `../dist/js/${fileDest}`), - format: 'umd', - globals, - name: 'bootstrap' - }, - external, - plugins -} diff --git a/es-bs-base/js/index.js b/es-bs-base/js/index.js deleted file mode 100644 index e2d1e6c78..000000000 --- a/es-bs-base/js/index.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): index.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -export { default as Alert } from './src/alert' -export { default as Button } from './src/button' -export { default as Carousel } from './src/carousel' -export { default as Collapse } from './src/collapse' -export { default as Dropdown } from './src/dropdown' -export { default as Modal } from './src/modal' -export { default as Popover } from './src/popover' -export { default as Scrollspy } from './src/scrollspy' -export { default as Tab } from './src/tab' -export { default as Toast } from './src/toast' -export { default as Tooltip } from './src/tooltip' -export { default as Util } from './src/util' diff --git a/es-bs-base/js/src/alert.js b/es-bs-base/js/src/alert.js deleted file mode 100644 index 8902c407d..000000000 --- a/es-bs-base/js/src/alert.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): alert.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' -import Util from './util' - -/** - * Constants - */ - -const NAME = 'alert' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.alert' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const JQUERY_NO_CONFLICT = $.fn[NAME] - -const CLASS_NAME_ALERT = 'alert' -const CLASS_NAME_FADE = 'fade' -const CLASS_NAME_SHOW = 'show' - -const EVENT_CLOSE = `close${EVENT_KEY}` -const EVENT_CLOSED = `closed${EVENT_KEY}` -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` - -const SELECTOR_DISMISS = '[data-dismiss="alert"]' - -/** - * Class definition - */ - -class Alert { - constructor(element) { - this._element = element - } - - // Getters - static get VERSION() { - return VERSION - } - - // Public - close(element) { - let rootElement = this._element - if (element) { - rootElement = this._getRootElement(element) - } - - const customEvent = this._triggerCloseEvent(rootElement) - - if (customEvent.isDefaultPrevented()) { - return - } - - this._removeElement(rootElement) - } - - dispose() { - $.removeData(this._element, DATA_KEY) - this._element = null - } - - // Private - _getRootElement(element) { - const selector = Util.getSelectorFromElement(element) - let parent = false - - if (selector) { - parent = document.querySelector(selector) - } - - if (!parent) { - parent = $(element).closest(`.${CLASS_NAME_ALERT}`)[0] - } - - return parent - } - - _triggerCloseEvent(element) { - const closeEvent = $.Event(EVENT_CLOSE) - - $(element).trigger(closeEvent) - return closeEvent - } - - _removeElement(element) { - $(element).removeClass(CLASS_NAME_SHOW) - - if (!$(element).hasClass(CLASS_NAME_FADE)) { - this._destroyElement(element) - return - } - - const transitionDuration = Util.getTransitionDurationFromElement(element) - - $(element) - .one(Util.TRANSITION_END, event => this._destroyElement(element, event)) - .emulateTransitionEnd(transitionDuration) - } - - _destroyElement(element) { - $(element) - .detach() - .trigger(EVENT_CLOSED) - .remove() - } - - // Static - static _jQueryInterface(config) { - return this.each(function () { - const $element = $(this) - let data = $element.data(DATA_KEY) - - if (!data) { - data = new Alert(this) - $element.data(DATA_KEY, data) - } - - if (config === 'close') { - data[config](this) - } - }) - } - - static _handleDismiss(alertInstance) { - return function (event) { - if (event) { - event.preventDefault() - } - - alertInstance.close(this) - } - } -} - -/** - * Data API implementation - */ - -$(document).on( - EVENT_CLICK_DATA_API, - SELECTOR_DISMISS, - Alert._handleDismiss(new Alert()) -) - -/** - * jQuery - */ - -$.fn[NAME] = Alert._jQueryInterface -$.fn[NAME].Constructor = Alert -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Alert._jQueryInterface -} - -export default Alert diff --git a/es-bs-base/js/src/button.js b/es-bs-base/js/src/button.js deleted file mode 100644 index 914008cc8..000000000 --- a/es-bs-base/js/src/button.js +++ /dev/null @@ -1,199 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): button.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' - -/** - * Constants - */ - -const NAME = 'button' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.button' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const JQUERY_NO_CONFLICT = $.fn[NAME] - -const CLASS_NAME_ACTIVE = 'active' -const CLASS_NAME_BUTTON = 'btn' -const CLASS_NAME_FOCUS = 'focus' - -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` -const EVENT_FOCUS_BLUR_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY} ` + - `blur${EVENT_KEY}${DATA_API_KEY}` -const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` - -const SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^="button"]' -const SELECTOR_DATA_TOGGLES = '[data-toggle="buttons"]' -const SELECTOR_DATA_TOGGLE = '[data-toggle="button"]' -const SELECTOR_DATA_TOGGLES_BUTTONS = '[data-toggle="buttons"] .btn' -const SELECTOR_INPUT = 'input:not([type="hidden"])' -const SELECTOR_ACTIVE = '.active' -const SELECTOR_BUTTON = '.btn' - -/** - * Class definition - */ - -class Button { - constructor(element) { - this._element = element - this.shouldAvoidTriggerChange = false - } - - // Getters - static get VERSION() { - return VERSION - } - - // Public - toggle() { - let triggerChangeEvent = true - let addAriaPressed = true - const rootElement = $(this._element).closest(SELECTOR_DATA_TOGGLES)[0] - - if (rootElement) { - const input = this._element.querySelector(SELECTOR_INPUT) - - if (input) { - if (input.type === 'radio') { - if (input.checked && this._element.classList.contains(CLASS_NAME_ACTIVE)) { - triggerChangeEvent = false - } else { - const activeElement = rootElement.querySelector(SELECTOR_ACTIVE) - - // eslint-disable-next-line max-depth - if (activeElement) { - $(activeElement).removeClass(CLASS_NAME_ACTIVE) - } - } - } - - if (triggerChangeEvent) { - // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input - if (input.type === 'checkbox' || input.type === 'radio') { - input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE) - } - - if (!this.shouldAvoidTriggerChange) { - $(input).trigger('change') - } - } - - input.focus() - addAriaPressed = false - } - } - - if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) { - if (addAriaPressed) { - this._element.setAttribute('aria-pressed', !this._element.classList.contains(CLASS_NAME_ACTIVE)) - } - - if (triggerChangeEvent) { - $(this._element).toggleClass(CLASS_NAME_ACTIVE) - } - } - } - - dispose() { - $.removeData(this._element, DATA_KEY) - this._element = null - } - - // Static - static _jQueryInterface(config, avoidTriggerChange) { - return this.each(function () { - const $element = $(this) - let data = $element.data(DATA_KEY) - - if (!data) { - data = new Button(this) - $element.data(DATA_KEY, data) - } - - data.shouldAvoidTriggerChange = avoidTriggerChange - - if (config === 'toggle') { - data[config]() - } - }) - } -} - -/** - * Data API implementation - */ - -$(document) - .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => { - let button = event.target - const initialButton = button - - if (!$(button).hasClass(CLASS_NAME_BUTTON)) { - button = $(button).closest(SELECTOR_BUTTON)[0] - } - - if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) { - event.preventDefault() // work around Firefox bug #1540995 - } else { - const inputBtn = button.querySelector(SELECTOR_INPUT) - - if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) { - event.preventDefault() // work around Firefox bug #1540995 - return - } - - if (initialButton.tagName === 'INPUT' || button.tagName !== 'LABEL') { - Button._jQueryInterface.call($(button), 'toggle', initialButton.tagName === 'INPUT') - } - } - }) - .on(EVENT_FOCUS_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => { - const button = $(event.target).closest(SELECTOR_BUTTON)[0] - $(button).toggleClass(CLASS_NAME_FOCUS, /^focus(in)?$/.test(event.type)) - }) - -$(window).on(EVENT_LOAD_DATA_API, () => { - // ensure correct active class is set to match the controls' actual values/states - - // find all checkboxes/readio buttons inside data-toggle groups - let buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLES_BUTTONS)) - for (let i = 0, len = buttons.length; i < len; i++) { - const button = buttons[i] - const input = button.querySelector(SELECTOR_INPUT) - if (input.checked || input.hasAttribute('checked')) { - button.classList.add(CLASS_NAME_ACTIVE) - } else { - button.classList.remove(CLASS_NAME_ACTIVE) - } - } - - // find all button toggles - buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE)) - for (let i = 0, len = buttons.length; i < len; i++) { - const button = buttons[i] - if (button.getAttribute('aria-pressed') === 'true') { - button.classList.add(CLASS_NAME_ACTIVE) - } else { - button.classList.remove(CLASS_NAME_ACTIVE) - } - } -}) - -/** - * jQuery - */ - -$.fn[NAME] = Button._jQueryInterface -$.fn[NAME].Constructor = Button -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Button._jQueryInterface -} - -export default Button diff --git a/es-bs-base/js/src/carousel.js b/es-bs-base/js/src/carousel.js deleted file mode 100644 index 3dd7ee213..000000000 --- a/es-bs-base/js/src/carousel.js +++ /dev/null @@ -1,604 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): carousel.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' -import Util from './util' - -/** - * Constants - */ - -const NAME = 'carousel' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.carousel' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const JQUERY_NO_CONFLICT = $.fn[NAME] -const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key -const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key -const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch -const SWIPE_THRESHOLD = 40 - -const CLASS_NAME_CAROUSEL = 'carousel' -const CLASS_NAME_ACTIVE = 'active' -const CLASS_NAME_SLIDE = 'slide' -const CLASS_NAME_RIGHT = 'carousel-item-right' -const CLASS_NAME_LEFT = 'carousel-item-left' -const CLASS_NAME_NEXT = 'carousel-item-next' -const CLASS_NAME_PREV = 'carousel-item-prev' -const CLASS_NAME_POINTER_EVENT = 'pointer-event' - -const DIRECTION_NEXT = 'next' -const DIRECTION_PREV = 'prev' -const DIRECTION_LEFT = 'left' -const DIRECTION_RIGHT = 'right' - -const EVENT_SLIDE = `slide${EVENT_KEY}` -const EVENT_SLID = `slid${EVENT_KEY}` -const EVENT_KEYDOWN = `keydown${EVENT_KEY}` -const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}` -const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}` -const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}` -const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}` -const EVENT_TOUCHEND = `touchend${EVENT_KEY}` -const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}` -const EVENT_POINTERUP = `pointerup${EVENT_KEY}` -const EVENT_DRAG_START = `dragstart${EVENT_KEY}` -const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` - -const SELECTOR_ACTIVE = '.active' -const SELECTOR_ACTIVE_ITEM = '.active.carousel-item' -const SELECTOR_ITEM = '.carousel-item' -const SELECTOR_ITEM_IMG = '.carousel-item img' -const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev' -const SELECTOR_INDICATORS = '.carousel-indicators' -const SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]' -const SELECTOR_DATA_RIDE = '[data-ride="carousel"]' - -const Default = { - interval: 5000, - keyboard: true, - slide: false, - pause: 'hover', - wrap: true, - touch: true -} - -const DefaultType = { - interval: '(number|boolean)', - keyboard: 'boolean', - slide: '(boolean|string)', - pause: '(string|boolean)', - wrap: 'boolean', - touch: 'boolean' -} - -const PointerType = { - TOUCH: 'touch', - PEN: 'pen' -} - -/** - * Class definition - */ - -class Carousel { - constructor(element, config) { - this._items = null - this._interval = null - this._activeElement = null - this._isPaused = false - this._isSliding = false - this.touchTimeout = null - this.touchStartX = 0 - this.touchDeltaX = 0 - - this._config = this._getConfig(config) - this._element = element - this._indicatorsElement = this._element.querySelector(SELECTOR_INDICATORS) - this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0 - this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent) - - this._addEventListeners() - } - - // Getters - static get VERSION() { - return VERSION - } - - static get Default() { - return Default - } - - // Public - next() { - if (!this._isSliding) { - this._slide(DIRECTION_NEXT) - } - } - - nextWhenVisible() { - const $element = $(this._element) - // Don't call next when the page isn't visible - // or the carousel or its parent isn't visible - if (!document.hidden && - ($element.is(':visible') && $element.css('visibility') !== 'hidden')) { - this.next() - } - } - - prev() { - if (!this._isSliding) { - this._slide(DIRECTION_PREV) - } - } - - pause(event) { - if (!event) { - this._isPaused = true - } - - if (this._element.querySelector(SELECTOR_NEXT_PREV)) { - Util.triggerTransitionEnd(this._element) - this.cycle(true) - } - - clearInterval(this._interval) - this._interval = null - } - - cycle(event) { - if (!event) { - this._isPaused = false - } - - if (this._interval) { - clearInterval(this._interval) - this._interval = null - } - - if (this._config.interval && !this._isPaused) { - this._updateInterval() - - this._interval = setInterval( - (document.visibilityState ? this.nextWhenVisible : this.next).bind(this), - this._config.interval - ) - } - } - - to(index) { - this._activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM) - - const activeIndex = this._getItemIndex(this._activeElement) - - if (index > this._items.length - 1 || index < 0) { - return - } - - if (this._isSliding) { - $(this._element).one(EVENT_SLID, () => this.to(index)) - return - } - - if (activeIndex === index) { - this.pause() - this.cycle() - return - } - - const direction = index > activeIndex ? - DIRECTION_NEXT : - DIRECTION_PREV - - this._slide(direction, this._items[index]) - } - - dispose() { - $(this._element).off(EVENT_KEY) - $.removeData(this._element, DATA_KEY) - - this._items = null - this._config = null - this._element = null - this._interval = null - this._isPaused = null - this._isSliding = null - this._activeElement = null - this._indicatorsElement = null - } - - // Private - _getConfig(config) { - config = { - ...Default, - ...config - } - Util.typeCheckConfig(NAME, config, DefaultType) - return config - } - - _handleSwipe() { - const absDeltax = Math.abs(this.touchDeltaX) - - if (absDeltax <= SWIPE_THRESHOLD) { - return - } - - const direction = absDeltax / this.touchDeltaX - - this.touchDeltaX = 0 - - // swipe left - if (direction > 0) { - this.prev() - } - - // swipe right - if (direction < 0) { - this.next() - } - } - - _addEventListeners() { - if (this._config.keyboard) { - $(this._element).on(EVENT_KEYDOWN, event => this._keydown(event)) - } - - if (this._config.pause === 'hover') { - $(this._element) - .on(EVENT_MOUSEENTER, event => this.pause(event)) - .on(EVENT_MOUSELEAVE, event => this.cycle(event)) - } - - if (this._config.touch) { - this._addTouchEventListeners() - } - } - - _addTouchEventListeners() { - if (!this._touchSupported) { - return - } - - const start = event => { - if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { - this.touchStartX = event.originalEvent.clientX - } else if (!this._pointerEvent) { - this.touchStartX = event.originalEvent.touches[0].clientX - } - } - - const move = event => { - // ensure swiping with one touch and not pinching - this.touchDeltaX = event.originalEvent.touches && event.originalEvent.touches.length > 1 ? - 0 : - event.originalEvent.touches[0].clientX - this.touchStartX - } - - const end = event => { - if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) { - this.touchDeltaX = event.originalEvent.clientX - this.touchStartX - } - - this._handleSwipe() - if (this._config.pause === 'hover') { - // If it's a touch-enabled device, mouseenter/leave are fired as - // part of the mouse compatibility events on first tap - the carousel - // would stop cycling until user tapped out of it; - // here, we listen for touchend, explicitly pause the carousel - // (as if it's the second time we tap on it, mouseenter compat event - // is NOT fired) and after a timeout (to allow for mouse compatibility - // events to fire) we explicitly restart cycling - - this.pause() - if (this.touchTimeout) { - clearTimeout(this.touchTimeout) - } - - this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval) - } - } - - $(this._element.querySelectorAll(SELECTOR_ITEM_IMG)) - .on(EVENT_DRAG_START, e => e.preventDefault()) - - if (this._pointerEvent) { - $(this._element).on(EVENT_POINTERDOWN, event => start(event)) - $(this._element).on(EVENT_POINTERUP, event => end(event)) - - this._element.classList.add(CLASS_NAME_POINTER_EVENT) - } else { - $(this._element).on(EVENT_TOUCHSTART, event => start(event)) - $(this._element).on(EVENT_TOUCHMOVE, event => move(event)) - $(this._element).on(EVENT_TOUCHEND, event => end(event)) - } - } - - _keydown(event) { - if (/input|textarea/i.test(event.target.tagName)) { - return - } - - switch (event.which) { - case ARROW_LEFT_KEYCODE: { - event.preventDefault() - this.prev() - break - } - - case ARROW_RIGHT_KEYCODE: { - event.preventDefault() - this.next() - break - } - - default: - } - } - - _getItemIndex(element) { - this._items = element && element.parentNode ? - [].slice.call(element.parentNode.querySelectorAll(SELECTOR_ITEM)) : - [] - return this._items.indexOf(element) - } - - _getItemByDirection(direction, activeElement) { - const isNextDirection = direction === DIRECTION_NEXT - const isPrevDirection = direction === DIRECTION_PREV - const activeIndex = this._getItemIndex(activeElement) - const lastItemIndex = this._items.length - 1 - const isGoingToWrap = isPrevDirection && activeIndex === 0 || - isNextDirection && activeIndex === lastItemIndex - - if (isGoingToWrap && !this._config.wrap) { - return activeElement - } - - const delta = direction === DIRECTION_PREV ? -1 : 1 - const itemIndex = (activeIndex + delta) % this._items.length - - return itemIndex === -1 ? - this._items[this._items.length - 1] : this._items[itemIndex] - } - - _triggerSlideEvent(relatedTarget, eventDirectionName) { - const targetIndex = this._getItemIndex(relatedTarget) - const fromIndex = this._getItemIndex(this._element.querySelector(SELECTOR_ACTIVE_ITEM)) - const slideEvent = $.Event(EVENT_SLIDE, { - relatedTarget, - direction: eventDirectionName, - from: fromIndex, - to: targetIndex - }) - - $(this._element).trigger(slideEvent) - - return slideEvent - } - - _setActiveIndicatorElement(element) { - if (this._indicatorsElement) { - const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(SELECTOR_ACTIVE)) - $(indicators).removeClass(CLASS_NAME_ACTIVE) - - const nextIndicator = this._indicatorsElement.children[ - this._getItemIndex(element) - ] - - if (nextIndicator) { - $(nextIndicator).addClass(CLASS_NAME_ACTIVE) - } - } - } - - _updateInterval() { - const element = this._activeElement || this._element.querySelector(SELECTOR_ACTIVE_ITEM) - - if (!element) { - return - } - - const elementInterval = parseInt(element.getAttribute('data-interval'), 10) - - if (elementInterval) { - this._config.defaultInterval = this._config.defaultInterval || this._config.interval - this._config.interval = elementInterval - } else { - this._config.interval = this._config.defaultInterval || this._config.interval - } - } - - _slide(direction, element) { - const activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM) - const activeElementIndex = this._getItemIndex(activeElement) - const nextElement = element || activeElement && - this._getItemByDirection(direction, activeElement) - const nextElementIndex = this._getItemIndex(nextElement) - const isCycling = Boolean(this._interval) - - let directionalClassName - let orderClassName - let eventDirectionName - - if (direction === DIRECTION_NEXT) { - directionalClassName = CLASS_NAME_LEFT - orderClassName = CLASS_NAME_NEXT - eventDirectionName = DIRECTION_LEFT - } else { - directionalClassName = CLASS_NAME_RIGHT - orderClassName = CLASS_NAME_PREV - eventDirectionName = DIRECTION_RIGHT - } - - if (nextElement && $(nextElement).hasClass(CLASS_NAME_ACTIVE)) { - this._isSliding = false - return - } - - const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName) - if (slideEvent.isDefaultPrevented()) { - return - } - - if (!activeElement || !nextElement) { - // Some weirdness is happening, so we bail - return - } - - this._isSliding = true - - if (isCycling) { - this.pause() - } - - this._setActiveIndicatorElement(nextElement) - this._activeElement = nextElement - - const slidEvent = $.Event(EVENT_SLID, { - relatedTarget: nextElement, - direction: eventDirectionName, - from: activeElementIndex, - to: nextElementIndex - }) - - if ($(this._element).hasClass(CLASS_NAME_SLIDE)) { - $(nextElement).addClass(orderClassName) - - Util.reflow(nextElement) - - $(activeElement).addClass(directionalClassName) - $(nextElement).addClass(directionalClassName) - - const transitionDuration = Util.getTransitionDurationFromElement(activeElement) - - $(activeElement) - .one(Util.TRANSITION_END, () => { - $(nextElement) - .removeClass(`${directionalClassName} ${orderClassName}`) - .addClass(CLASS_NAME_ACTIVE) - - $(activeElement).removeClass(`${CLASS_NAME_ACTIVE} ${orderClassName} ${directionalClassName}`) - - this._isSliding = false - - setTimeout(() => $(this._element).trigger(slidEvent), 0) - }) - .emulateTransitionEnd(transitionDuration) - } else { - $(activeElement).removeClass(CLASS_NAME_ACTIVE) - $(nextElement).addClass(CLASS_NAME_ACTIVE) - - this._isSliding = false - $(this._element).trigger(slidEvent) - } - - if (isCycling) { - this.cycle() - } - } - - // Static - static _jQueryInterface(config) { - return this.each(function () { - let data = $(this).data(DATA_KEY) - let _config = { - ...Default, - ...$(this).data() - } - - if (typeof config === 'object') { - _config = { - ..._config, - ...config - } - } - - const action = typeof config === 'string' ? config : _config.slide - - if (!data) { - data = new Carousel(this, _config) - $(this).data(DATA_KEY, data) - } - - if (typeof config === 'number') { - data.to(config) - } else if (typeof action === 'string') { - if (typeof data[action] === 'undefined') { - throw new TypeError(`No method named "${action}"`) - } - - data[action]() - } else if (_config.interval && _config.ride) { - data.pause() - data.cycle() - } - }) - } - - static _dataApiClickHandler(event) { - const selector = Util.getSelectorFromElement(this) - - if (!selector) { - return - } - - const target = $(selector)[0] - - if (!target || !$(target).hasClass(CLASS_NAME_CAROUSEL)) { - return - } - - const config = { - ...$(target).data(), - ...$(this).data() - } - const slideIndex = this.getAttribute('data-slide-to') - - if (slideIndex) { - config.interval = false - } - - Carousel._jQueryInterface.call($(target), config) - - if (slideIndex) { - $(target).data(DATA_KEY).to(slideIndex) - } - - event.preventDefault() - } -} - -/** - * Data API implementation - */ - -$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel._dataApiClickHandler) - -$(window).on(EVENT_LOAD_DATA_API, () => { - const carousels = [].slice.call(document.querySelectorAll(SELECTOR_DATA_RIDE)) - for (let i = 0, len = carousels.length; i < len; i++) { - const $carousel = $(carousels[i]) - Carousel._jQueryInterface.call($carousel, $carousel.data()) - } -}) - -/** - * jQuery - */ - -$.fn[NAME] = Carousel._jQueryInterface -$.fn[NAME].Constructor = Carousel -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Carousel._jQueryInterface -} - -export default Carousel diff --git a/es-bs-base/js/src/collapse.js b/es-bs-base/js/src/collapse.js deleted file mode 100644 index 0b9651c32..000000000 --- a/es-bs-base/js/src/collapse.js +++ /dev/null @@ -1,380 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): collapse.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' -import Util from './util' - -/** - * Constants - */ - -const NAME = 'collapse' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.collapse' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const JQUERY_NO_CONFLICT = $.fn[NAME] - -const CLASS_NAME_SHOW = 'show' -const CLASS_NAME_COLLAPSE = 'collapse' -const CLASS_NAME_COLLAPSING = 'collapsing' -const CLASS_NAME_COLLAPSED = 'collapsed' - -const DIMENSION_WIDTH = 'width' -const DIMENSION_HEIGHT = 'height' - -const EVENT_SHOW = `show${EVENT_KEY}` -const EVENT_SHOWN = `shown${EVENT_KEY}` -const EVENT_HIDE = `hide${EVENT_KEY}` -const EVENT_HIDDEN = `hidden${EVENT_KEY}` -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` - -const SELECTOR_ACTIVES = '.show, .collapsing' -const SELECTOR_DATA_TOGGLE = '[data-toggle="collapse"]' - -const Default = { - toggle: true, - parent: '' -} - -const DefaultType = { - toggle: 'boolean', - parent: '(string|element)' -} - -/** - * Class definition - */ - -class Collapse { - constructor(element, config) { - this._isTransitioning = false - this._element = element - this._config = this._getConfig(config) - this._triggerArray = [].slice.call(document.querySelectorAll( - `[data-toggle="collapse"][href="#${element.id}"],` + - `[data-toggle="collapse"][data-target="#${element.id}"]` - )) - - const toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE)) - for (let i = 0, len = toggleList.length; i < len; i++) { - const elem = toggleList[i] - const selector = Util.getSelectorFromElement(elem) - const filterElement = [].slice.call(document.querySelectorAll(selector)) - .filter(foundElem => foundElem === element) - - if (selector !== null && filterElement.length > 0) { - this._selector = selector - this._triggerArray.push(elem) - } - } - - this._parent = this._config.parent ? this._getParent() : null - - if (!this._config.parent) { - this._addAriaAndCollapsedClass(this._element, this._triggerArray) - } - - if (this._config.toggle) { - this.toggle() - } - } - - // Getters - static get VERSION() { - return VERSION - } - - static get Default() { - return Default - } - - // Public - toggle() { - if ($(this._element).hasClass(CLASS_NAME_SHOW)) { - this.hide() - } else { - this.show() - } - } - - show() { - if (this._isTransitioning || - $(this._element).hasClass(CLASS_NAME_SHOW)) { - return - } - - let actives - let activesData - - if (this._parent) { - actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES)) - .filter(elem => { - if (typeof this._config.parent === 'string') { - return elem.getAttribute('data-parent') === this._config.parent - } - - return elem.classList.contains(CLASS_NAME_COLLAPSE) - }) - - if (actives.length === 0) { - actives = null - } - } - - if (actives) { - activesData = $(actives).not(this._selector).data(DATA_KEY) - if (activesData && activesData._isTransitioning) { - return - } - } - - const startEvent = $.Event(EVENT_SHOW) - $(this._element).trigger(startEvent) - if (startEvent.isDefaultPrevented()) { - return - } - - if (actives) { - Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide') - if (!activesData) { - $(actives).data(DATA_KEY, null) - } - } - - const dimension = this._getDimension() - - $(this._element) - .removeClass(CLASS_NAME_COLLAPSE) - .addClass(CLASS_NAME_COLLAPSING) - - this._element.style[dimension] = 0 - - if (this._triggerArray.length) { - $(this._triggerArray) - .removeClass(CLASS_NAME_COLLAPSED) - .attr('aria-expanded', true) - } - - this.setTransitioning(true) - - const complete = () => { - $(this._element) - .removeClass(CLASS_NAME_COLLAPSING) - .addClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`) - - this._element.style[dimension] = '' - - this.setTransitioning(false) - - $(this._element).trigger(EVENT_SHOWN) - } - - const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1) - const scrollSize = `scroll${capitalizedDimension}` - const transitionDuration = Util.getTransitionDurationFromElement(this._element) - - $(this._element) - .one(Util.TRANSITION_END, complete) - .emulateTransitionEnd(transitionDuration) - - this._element.style[dimension] = `${this._element[scrollSize]}px` - } - - hide() { - if (this._isTransitioning || - !$(this._element).hasClass(CLASS_NAME_SHOW)) { - return - } - - const startEvent = $.Event(EVENT_HIDE) - $(this._element).trigger(startEvent) - if (startEvent.isDefaultPrevented()) { - return - } - - const dimension = this._getDimension() - - this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px` - - Util.reflow(this._element) - - $(this._element) - .addClass(CLASS_NAME_COLLAPSING) - .removeClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`) - - const triggerArrayLength = this._triggerArray.length - if (triggerArrayLength > 0) { - for (let i = 0; i < triggerArrayLength; i++) { - const trigger = this._triggerArray[i] - const selector = Util.getSelectorFromElement(trigger) - - if (selector !== null) { - const $elem = $([].slice.call(document.querySelectorAll(selector))) - if (!$elem.hasClass(CLASS_NAME_SHOW)) { - $(trigger).addClass(CLASS_NAME_COLLAPSED) - .attr('aria-expanded', false) - } - } - } - } - - this.setTransitioning(true) - - const complete = () => { - this.setTransitioning(false) - $(this._element) - .removeClass(CLASS_NAME_COLLAPSING) - .addClass(CLASS_NAME_COLLAPSE) - .trigger(EVENT_HIDDEN) - } - - this._element.style[dimension] = '' - const transitionDuration = Util.getTransitionDurationFromElement(this._element) - - $(this._element) - .one(Util.TRANSITION_END, complete) - .emulateTransitionEnd(transitionDuration) - } - - setTransitioning(isTransitioning) { - this._isTransitioning = isTransitioning - } - - dispose() { - $.removeData(this._element, DATA_KEY) - - this._config = null - this._parent = null - this._element = null - this._triggerArray = null - this._isTransitioning = null - } - - // Private - _getConfig(config) { - config = { - ...Default, - ...config - } - config.toggle = Boolean(config.toggle) // Coerce string values - Util.typeCheckConfig(NAME, config, DefaultType) - return config - } - - _getDimension() { - const hasWidth = $(this._element).hasClass(DIMENSION_WIDTH) - return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT - } - - _getParent() { - let parent - - if (Util.isElement(this._config.parent)) { - parent = this._config.parent - - // It's a jQuery object - if (typeof this._config.parent.jquery !== 'undefined') { - parent = this._config.parent[0] - } - } else { - parent = document.querySelector(this._config.parent) - } - - const selector = `[data-toggle="collapse"][data-parent="${this._config.parent}"]` - const children = [].slice.call(parent.querySelectorAll(selector)) - - $(children).each((i, element) => { - this._addAriaAndCollapsedClass( - Collapse._getTargetFromElement(element), - [element] - ) - }) - - return parent - } - - _addAriaAndCollapsedClass(element, triggerArray) { - const isOpen = $(element).hasClass(CLASS_NAME_SHOW) - - if (triggerArray.length) { - $(triggerArray) - .toggleClass(CLASS_NAME_COLLAPSED, !isOpen) - .attr('aria-expanded', isOpen) - } - } - - // Static - static _getTargetFromElement(element) { - const selector = Util.getSelectorFromElement(element) - return selector ? document.querySelector(selector) : null - } - - static _jQueryInterface(config) { - return this.each(function () { - const $element = $(this) - let data = $element.data(DATA_KEY) - const _config = { - ...Default, - ...$element.data(), - ...(typeof config === 'object' && config ? config : {}) - } - - if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) { - _config.toggle = false - } - - if (!data) { - data = new Collapse(this, _config) - $element.data(DATA_KEY, data) - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError(`No method named "${config}"`) - } - - data[config]() - } - }) - } -} - -/** - * Data API implementation - */ - -$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { - // preventDefault only for elements (which change the URL) not inside the collapsible element - if (event.currentTarget.tagName === 'A') { - event.preventDefault() - } - - const $trigger = $(this) - const selector = Util.getSelectorFromElement(this) - const selectors = [].slice.call(document.querySelectorAll(selector)) - - $(selectors).each(function () { - const $target = $(this) - const data = $target.data(DATA_KEY) - const config = data ? 'toggle' : $trigger.data() - Collapse._jQueryInterface.call($target, config) - }) -}) - -/** - * jQuery - */ - -$.fn[NAME] = Collapse._jQueryInterface -$.fn[NAME].Constructor = Collapse -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Collapse._jQueryInterface -} - -export default Collapse diff --git a/es-bs-base/js/src/dropdown.js b/es-bs-base/js/src/dropdown.js deleted file mode 100644 index 1403fd9ee..000000000 --- a/es-bs-base/js/src/dropdown.js +++ /dev/null @@ -1,523 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): dropdown.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' -import Popper from 'popper.js' -import Util from './util' - -/** - * Constants - */ - -const NAME = 'dropdown' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.dropdown' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const JQUERY_NO_CONFLICT = $.fn[NAME] -const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key -const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key -const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key -const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key -const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key -const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse) -const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`) - -const CLASS_NAME_DISABLED = 'disabled' -const CLASS_NAME_SHOW = 'show' -const CLASS_NAME_DROPUP = 'dropup' -const CLASS_NAME_DROPRIGHT = 'dropright' -const CLASS_NAME_DROPLEFT = 'dropleft' -const CLASS_NAME_MENURIGHT = 'dropdown-menu-right' -const CLASS_NAME_POSITION_STATIC = 'position-static' - -const EVENT_HIDE = `hide${EVENT_KEY}` -const EVENT_HIDDEN = `hidden${EVENT_KEY}` -const EVENT_SHOW = `show${EVENT_KEY}` -const EVENT_SHOWN = `shown${EVENT_KEY}` -const EVENT_CLICK = `click${EVENT_KEY}` -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` -const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}` -const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}` - -const SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]' -const SELECTOR_FORM_CHILD = '.dropdown form' -const SELECTOR_MENU = '.dropdown-menu' -const SELECTOR_NAVBAR_NAV = '.navbar-nav' -const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)' - -const PLACEMENT_TOP = 'top-start' -const PLACEMENT_TOPEND = 'top-end' -const PLACEMENT_BOTTOM = 'bottom-start' -const PLACEMENT_BOTTOMEND = 'bottom-end' -const PLACEMENT_RIGHT = 'right-start' -const PLACEMENT_LEFT = 'left-start' - -const Default = { - offset: 0, - flip: true, - boundary: 'scrollParent', - reference: 'toggle', - display: 'dynamic', - popperConfig: null -} - -const DefaultType = { - offset: '(number|string|function)', - flip: 'boolean', - boundary: '(string|element)', - reference: '(string|element)', - display: 'string', - popperConfig: '(null|object)' -} - -/** - * Class definition - */ - -class Dropdown { - constructor(element, config) { - this._element = element - this._popper = null - this._config = this._getConfig(config) - this._menu = this._getMenuElement() - this._inNavbar = this._detectNavbar() - - this._addEventListeners() - } - - // Getters - static get VERSION() { - return VERSION - } - - static get Default() { - return Default - } - - static get DefaultType() { - return DefaultType - } - - // Public - toggle() { - if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED)) { - return - } - - const isActive = $(this._menu).hasClass(CLASS_NAME_SHOW) - - Dropdown._clearMenus() - - if (isActive) { - return - } - - this.show(true) - } - - show(usePopper = false) { - if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || $(this._menu).hasClass(CLASS_NAME_SHOW)) { - return - } - - const relatedTarget = { - relatedTarget: this._element - } - const showEvent = $.Event(EVENT_SHOW, relatedTarget) - const parent = Dropdown._getParentFromElement(this._element) - - $(parent).trigger(showEvent) - - if (showEvent.isDefaultPrevented()) { - return - } - - // Totally disable Popper for Dropdowns in Navbar - if (!this._inNavbar && usePopper) { - // Check for Popper dependency - if (typeof Popper === 'undefined') { - throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)') - } - - let referenceElement = this._element - - if (this._config.reference === 'parent') { - referenceElement = parent - } else if (Util.isElement(this._config.reference)) { - referenceElement = this._config.reference - - // Check if it's jQuery element - if (typeof this._config.reference.jquery !== 'undefined') { - referenceElement = this._config.reference[0] - } - } - - // If boundary is not `scrollParent`, then set position to `static` - // to allow the menu to "escape" the scroll parent's boundaries - // https://github.com/twbs/bootstrap/issues/24251 - if (this._config.boundary !== 'scrollParent') { - $(parent).addClass(CLASS_NAME_POSITION_STATIC) - } - - this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig()) - } - - // If this is a touch-enabled device we add extra - // empty mouseover listeners to the body's immediate children; - // only needed because of broken event delegation on iOS - // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html - if ('ontouchstart' in document.documentElement && - $(parent).closest(SELECTOR_NAVBAR_NAV).length === 0) { - $(document.body).children().on('mouseover', null, $.noop) - } - - this._element.focus() - this._element.setAttribute('aria-expanded', true) - - $(this._menu).toggleClass(CLASS_NAME_SHOW) - $(parent) - .toggleClass(CLASS_NAME_SHOW) - .trigger($.Event(EVENT_SHOWN, relatedTarget)) - } - - hide() { - if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || !$(this._menu).hasClass(CLASS_NAME_SHOW)) { - return - } - - const relatedTarget = { - relatedTarget: this._element - } - const hideEvent = $.Event(EVENT_HIDE, relatedTarget) - const parent = Dropdown._getParentFromElement(this._element) - - $(parent).trigger(hideEvent) - - if (hideEvent.isDefaultPrevented()) { - return - } - - if (this._popper) { - this._popper.destroy() - } - - $(this._menu).toggleClass(CLASS_NAME_SHOW) - $(parent) - .toggleClass(CLASS_NAME_SHOW) - .trigger($.Event(EVENT_HIDDEN, relatedTarget)) - } - - dispose() { - $.removeData(this._element, DATA_KEY) - $(this._element).off(EVENT_KEY) - this._element = null - this._menu = null - if (this._popper !== null) { - this._popper.destroy() - this._popper = null - } - } - - update() { - this._inNavbar = this._detectNavbar() - if (this._popper !== null) { - this._popper.scheduleUpdate() - } - } - - // Private - _addEventListeners() { - $(this._element).on(EVENT_CLICK, event => { - event.preventDefault() - event.stopPropagation() - this.toggle() - }) - } - - _getConfig(config) { - config = { - ...this.constructor.Default, - ...$(this._element).data(), - ...config - } - - Util.typeCheckConfig( - NAME, - config, - this.constructor.DefaultType - ) - - return config - } - - _getMenuElement() { - if (!this._menu) { - const parent = Dropdown._getParentFromElement(this._element) - - if (parent) { - this._menu = parent.querySelector(SELECTOR_MENU) - } - } - - return this._menu - } - - _getPlacement() { - const $parentDropdown = $(this._element.parentNode) - let placement = PLACEMENT_BOTTOM - - // Handle dropup - if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) { - placement = $(this._menu).hasClass(CLASS_NAME_MENURIGHT) ? - PLACEMENT_TOPEND : - PLACEMENT_TOP - } else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) { - placement = PLACEMENT_RIGHT - } else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) { - placement = PLACEMENT_LEFT - } else if ($(this._menu).hasClass(CLASS_NAME_MENURIGHT)) { - placement = PLACEMENT_BOTTOMEND - } - - return placement - } - - _detectNavbar() { - return $(this._element).closest('.navbar').length > 0 - } - - _getOffset() { - const offset = {} - - if (typeof this._config.offset === 'function') { - offset.fn = data => { - data.offsets = { - ...data.offsets, - ...this._config.offset(data.offsets, this._element) - } - - return data - } - } else { - offset.offset = this._config.offset - } - - return offset - } - - _getPopperConfig() { - const popperConfig = { - placement: this._getPlacement(), - modifiers: { - offset: this._getOffset(), - flip: { - enabled: this._config.flip - }, - preventOverflow: { - boundariesElement: this._config.boundary - } - } - } - - // Disable Popper if we have a static display - if (this._config.display === 'static') { - popperConfig.modifiers.applyStyle = { - enabled: false - } - } - - return { - ...popperConfig, - ...this._config.popperConfig - } - } - - // Static - static _jQueryInterface(config) { - return this.each(function () { - let data = $(this).data(DATA_KEY) - const _config = typeof config === 'object' ? config : null - - if (!data) { - data = new Dropdown(this, _config) - $(this).data(DATA_KEY, data) - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError(`No method named "${config}"`) - } - - data[config]() - } - }) - } - - static _clearMenus(event) { - if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || - event.type === 'keyup' && event.which !== TAB_KEYCODE)) { - return - } - - const toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE)) - - for (let i = 0, len = toggles.length; i < len; i++) { - const parent = Dropdown._getParentFromElement(toggles[i]) - const context = $(toggles[i]).data(DATA_KEY) - const relatedTarget = { - relatedTarget: toggles[i] - } - - if (event && event.type === 'click') { - relatedTarget.clickEvent = event - } - - if (!context) { - continue - } - - const dropdownMenu = context._menu - if (!$(parent).hasClass(CLASS_NAME_SHOW)) { - continue - } - - if (event && (event.type === 'click' && - /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && - $.contains(parent, event.target)) { - continue - } - - const hideEvent = $.Event(EVENT_HIDE, relatedTarget) - $(parent).trigger(hideEvent) - if (hideEvent.isDefaultPrevented()) { - continue - } - - // If this is a touch-enabled device we remove the extra - // empty mouseover listeners we added for iOS support - if ('ontouchstart' in document.documentElement) { - $(document.body).children().off('mouseover', null, $.noop) - } - - toggles[i].setAttribute('aria-expanded', 'false') - - if (context._popper) { - context._popper.destroy() - } - - $(dropdownMenu).removeClass(CLASS_NAME_SHOW) - $(parent) - .removeClass(CLASS_NAME_SHOW) - .trigger($.Event(EVENT_HIDDEN, relatedTarget)) - } - } - - static _getParentFromElement(element) { - let parent - const selector = Util.getSelectorFromElement(element) - - if (selector) { - parent = document.querySelector(selector) - } - - return parent || element.parentNode - } - - // eslint-disable-next-line complexity - static _dataApiKeydownHandler(event) { - // If not input/textarea: - // - And not a key in REGEXP_KEYDOWN => not a dropdown command - // If input/textarea: - // - If space key => not a dropdown command - // - If key is other than escape - // - If key is not up or down => not a dropdown command - // - If trigger inside the menu => not a dropdown command - if (/input|textarea/i.test(event.target.tagName) ? - event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && - (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || - $(event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) { - return - } - - if (this.disabled || $(this).hasClass(CLASS_NAME_DISABLED)) { - return - } - - const parent = Dropdown._getParentFromElement(this) - const isActive = $(parent).hasClass(CLASS_NAME_SHOW) - - if (!isActive && event.which === ESCAPE_KEYCODE) { - return - } - - event.preventDefault() - event.stopPropagation() - - if (!isActive || (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) { - if (event.which === ESCAPE_KEYCODE) { - $(parent.querySelector(SELECTOR_DATA_TOGGLE)).trigger('focus') - } - - $(this).trigger('click') - return - } - - const items = [].slice.call(parent.querySelectorAll(SELECTOR_VISIBLE_ITEMS)) - .filter(item => $(item).is(':visible')) - - if (items.length === 0) { - return - } - - let index = items.indexOf(event.target) - - if (event.which === ARROW_UP_KEYCODE && index > 0) { // Up - index-- - } - - if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { // Down - index++ - } - - if (index < 0) { - index = 0 - } - - items[index].focus() - } -} - -/** - * Data API implementation - */ - -$(document) - .on(EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown._dataApiKeydownHandler) - .on(EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown._dataApiKeydownHandler) - .on(`${EVENT_CLICK_DATA_API} ${EVENT_KEYUP_DATA_API}`, Dropdown._clearMenus) - .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { - event.preventDefault() - event.stopPropagation() - Dropdown._jQueryInterface.call($(this), 'toggle') - }) - .on(EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => { - e.stopPropagation() - }) - -/** - * jQuery - */ - -$.fn[NAME] = Dropdown._jQueryInterface -$.fn[NAME].Constructor = Dropdown -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Dropdown._jQueryInterface -} - -export default Dropdown diff --git a/es-bs-base/js/src/modal.js b/es-bs-base/js/src/modal.js deleted file mode 100644 index 8b8281a13..000000000 --- a/es-bs-base/js/src/modal.js +++ /dev/null @@ -1,620 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): modal.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' -import Util from './util' - -/** - * Constants - */ - -const NAME = 'modal' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.modal' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const JQUERY_NO_CONFLICT = $.fn[NAME] -const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key - -const CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable' -const CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure' -const CLASS_NAME_BACKDROP = 'modal-backdrop' -const CLASS_NAME_OPEN = 'modal-open' -const CLASS_NAME_FADE = 'fade' -const CLASS_NAME_SHOW = 'show' -const CLASS_NAME_STATIC = 'modal-static' - -const EVENT_HIDE = `hide${EVENT_KEY}` -const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}` -const EVENT_HIDDEN = `hidden${EVENT_KEY}` -const EVENT_SHOW = `show${EVENT_KEY}` -const EVENT_SHOWN = `shown${EVENT_KEY}` -const EVENT_FOCUSIN = `focusin${EVENT_KEY}` -const EVENT_RESIZE = `resize${EVENT_KEY}` -const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}` -const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}` -const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}` -const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}` -const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}` - -const SELECTOR_DIALOG = '.modal-dialog' -const SELECTOR_MODAL_BODY = '.modal-body' -const SELECTOR_DATA_TOGGLE = '[data-toggle="modal"]' -const SELECTOR_DATA_DISMISS = '[data-dismiss="modal"]' -const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top' -const SELECTOR_STICKY_CONTENT = '.sticky-top' - -const Default = { - backdrop: true, - keyboard: true, - focus: true, - show: true -} - -const DefaultType = { - backdrop: '(boolean|string)', - keyboard: 'boolean', - focus: 'boolean', - show: 'boolean' -} - -/** - * Class definition - */ - -class Modal { - constructor(element, config) { - this._config = this._getConfig(config) - this._element = element - this._dialog = element.querySelector(SELECTOR_DIALOG) - this._backdrop = null - this._isShown = false - this._isBodyOverflowing = false - this._ignoreBackdropClick = false - this._isTransitioning = false - this._scrollbarWidth = 0 - } - - // Getters - static get VERSION() { - return VERSION - } - - static get Default() { - return Default - } - - // Public - toggle(relatedTarget) { - return this._isShown ? this.hide() : this.show(relatedTarget) - } - - show(relatedTarget) { - if (this._isShown || this._isTransitioning) { - return - } - - const showEvent = $.Event(EVENT_SHOW, { - relatedTarget - }) - - $(this._element).trigger(showEvent) - - if (showEvent.isDefaultPrevented()) { - return - } - - this._isShown = true - - if ($(this._element).hasClass(CLASS_NAME_FADE)) { - this._isTransitioning = true - } - - this._checkScrollbar() - this._setScrollbar() - - this._adjustDialog() - - this._setEscapeEvent() - this._setResizeEvent() - - $(this._element).on( - EVENT_CLICK_DISMISS, - SELECTOR_DATA_DISMISS, - event => this.hide(event) - ) - - $(this._dialog).on(EVENT_MOUSEDOWN_DISMISS, () => { - $(this._element).one(EVENT_MOUSEUP_DISMISS, event => { - if ($(event.target).is(this._element)) { - this._ignoreBackdropClick = true - } - }) - }) - - this._showBackdrop(() => this._showElement(relatedTarget)) - } - - hide(event) { - if (event) { - event.preventDefault() - } - - if (!this._isShown || this._isTransitioning) { - return - } - - const hideEvent = $.Event(EVENT_HIDE) - - $(this._element).trigger(hideEvent) - - if (!this._isShown || hideEvent.isDefaultPrevented()) { - return - } - - this._isShown = false - const transition = $(this._element).hasClass(CLASS_NAME_FADE) - - if (transition) { - this._isTransitioning = true - } - - this._setEscapeEvent() - this._setResizeEvent() - - $(document).off(EVENT_FOCUSIN) - - $(this._element).removeClass(CLASS_NAME_SHOW) - - $(this._element).off(EVENT_CLICK_DISMISS) - $(this._dialog).off(EVENT_MOUSEDOWN_DISMISS) - - if (transition) { - const transitionDuration = Util.getTransitionDurationFromElement(this._element) - - $(this._element) - .one(Util.TRANSITION_END, event => this._hideModal(event)) - .emulateTransitionEnd(transitionDuration) - } else { - this._hideModal() - } - } - - dispose() { - [window, this._element, this._dialog] - .forEach(htmlElement => $(htmlElement).off(EVENT_KEY)) - - /** - * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API` - * Do not move `document` in `htmlElements` array - * It will remove `EVENT_CLICK_DATA_API` event that should remain - */ - $(document).off(EVENT_FOCUSIN) - - $.removeData(this._element, DATA_KEY) - - this._config = null - this._element = null - this._dialog = null - this._backdrop = null - this._isShown = null - this._isBodyOverflowing = null - this._ignoreBackdropClick = null - this._isTransitioning = null - this._scrollbarWidth = null - } - - handleUpdate() { - this._adjustDialog() - } - - // Private - _getConfig(config) { - config = { - ...Default, - ...config - } - Util.typeCheckConfig(NAME, config, DefaultType) - return config - } - - _triggerBackdropTransition() { - const hideEventPrevented = $.Event(EVENT_HIDE_PREVENTED) - - $(this._element).trigger(hideEventPrevented) - if (hideEventPrevented.isDefaultPrevented()) { - return - } - - const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight - - if (!isModalOverflowing) { - this._element.style.overflowY = 'hidden' - } - - this._element.classList.add(CLASS_NAME_STATIC) - - const modalTransitionDuration = Util.getTransitionDurationFromElement(this._dialog) - $(this._element).off(Util.TRANSITION_END) - - $(this._element).one(Util.TRANSITION_END, () => { - this._element.classList.remove(CLASS_NAME_STATIC) - if (!isModalOverflowing) { - $(this._element).one(Util.TRANSITION_END, () => { - this._element.style.overflowY = '' - }) - .emulateTransitionEnd(this._element, modalTransitionDuration) - } - }) - .emulateTransitionEnd(modalTransitionDuration) - this._element.focus() - } - - _showElement(relatedTarget) { - const transition = $(this._element).hasClass(CLASS_NAME_FADE) - const modalBody = this._dialog ? this._dialog.querySelector(SELECTOR_MODAL_BODY) : null - - if (!this._element.parentNode || - this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { - // Don't move modal's DOM position - document.body.appendChild(this._element) - } - - this._element.style.display = 'block' - this._element.removeAttribute('aria-hidden') - this._element.setAttribute('aria-modal', true) - this._element.setAttribute('role', 'dialog') - - if ($(this._dialog).hasClass(CLASS_NAME_SCROLLABLE) && modalBody) { - modalBody.scrollTop = 0 - } else { - this._element.scrollTop = 0 - } - - if (transition) { - Util.reflow(this._element) - } - - $(this._element).addClass(CLASS_NAME_SHOW) - - if (this._config.focus) { - this._enforceFocus() - } - - const shownEvent = $.Event(EVENT_SHOWN, { - relatedTarget - }) - - const transitionComplete = () => { - if (this._config.focus) { - this._element.focus() - } - - this._isTransitioning = false - $(this._element).trigger(shownEvent) - } - - if (transition) { - const transitionDuration = Util.getTransitionDurationFromElement(this._dialog) - - $(this._dialog) - .one(Util.TRANSITION_END, transitionComplete) - .emulateTransitionEnd(transitionDuration) - } else { - transitionComplete() - } - } - - _enforceFocus() { - $(document) - .off(EVENT_FOCUSIN) // Guard against infinite focus loop - .on(EVENT_FOCUSIN, event => { - if (document !== event.target && - this._element !== event.target && - $(this._element).has(event.target).length === 0) { - this._element.focus() - } - }) - } - - _setEscapeEvent() { - if (this._isShown) { - $(this._element).on(EVENT_KEYDOWN_DISMISS, event => { - if (this._config.keyboard && event.which === ESCAPE_KEYCODE) { - event.preventDefault() - this.hide() - } else if (!this._config.keyboard && event.which === ESCAPE_KEYCODE) { - this._triggerBackdropTransition() - } - }) - } else if (!this._isShown) { - $(this._element).off(EVENT_KEYDOWN_DISMISS) - } - } - - _setResizeEvent() { - if (this._isShown) { - $(window).on(EVENT_RESIZE, event => this.handleUpdate(event)) - } else { - $(window).off(EVENT_RESIZE) - } - } - - _hideModal() { - this._element.style.display = 'none' - this._element.setAttribute('aria-hidden', true) - this._element.removeAttribute('aria-modal') - this._element.removeAttribute('role') - this._isTransitioning = false - this._showBackdrop(() => { - $(document.body).removeClass(CLASS_NAME_OPEN) - this._resetAdjustments() - this._resetScrollbar() - $(this._element).trigger(EVENT_HIDDEN) - }) - } - - _removeBackdrop() { - if (this._backdrop) { - $(this._backdrop).remove() - this._backdrop = null - } - } - - _showBackdrop(callback) { - const animate = $(this._element).hasClass(CLASS_NAME_FADE) ? - CLASS_NAME_FADE : '' - - if (this._isShown && this._config.backdrop) { - this._backdrop = document.createElement('div') - this._backdrop.className = CLASS_NAME_BACKDROP - - if (animate) { - this._backdrop.classList.add(animate) - } - - $(this._backdrop).appendTo(document.body) - - $(this._element).on(EVENT_CLICK_DISMISS, event => { - if (this._ignoreBackdropClick) { - this._ignoreBackdropClick = false - return - } - - if (event.target !== event.currentTarget) { - return - } - - if (this._config.backdrop === 'static') { - this._triggerBackdropTransition() - } else { - this.hide() - } - }) - - if (animate) { - Util.reflow(this._backdrop) - } - - $(this._backdrop).addClass(CLASS_NAME_SHOW) - - if (!callback) { - return - } - - if (!animate) { - callback() - return - } - - const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) - - $(this._backdrop) - .one(Util.TRANSITION_END, callback) - .emulateTransitionEnd(backdropTransitionDuration) - } else if (!this._isShown && this._backdrop) { - $(this._backdrop).removeClass(CLASS_NAME_SHOW) - - const callbackRemove = () => { - this._removeBackdrop() - if (callback) { - callback() - } - } - - if ($(this._element).hasClass(CLASS_NAME_FADE)) { - const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop) - - $(this._backdrop) - .one(Util.TRANSITION_END, callbackRemove) - .emulateTransitionEnd(backdropTransitionDuration) - } else { - callbackRemove() - } - } else if (callback) { - callback() - } - } - - // ---------------------------------------------------------------------- - // the following methods are used to handle overflowing modals - // eslint-disable-next-line no-warning-comments - // TODO: these should probably be refactored out of modal.js - // ---------------------------------------------------------------------- - - _adjustDialog() { - const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight - - if (!this._isBodyOverflowing && isModalOverflowing) { - this._element.style.paddingLeft = `${this._scrollbarWidth}px` - } - - if (this._isBodyOverflowing && !isModalOverflowing) { - this._element.style.paddingRight = `${this._scrollbarWidth}px` - } - } - - _resetAdjustments() { - this._element.style.paddingLeft = '' - this._element.style.paddingRight = '' - } - - _checkScrollbar() { - const rect = document.body.getBoundingClientRect() - this._isBodyOverflowing = Math.round(rect.left + rect.right) < window.innerWidth - this._scrollbarWidth = this._getScrollbarWidth() - } - - _setScrollbar() { - if (this._isBodyOverflowing) { - // Note: DOMNode.style.paddingRight returns the actual value or '' if not set - // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set - const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT)) - const stickyContent = [].slice.call(document.querySelectorAll(SELECTOR_STICKY_CONTENT)) - - // Adjust fixed content padding - $(fixedContent).each((index, element) => { - const actualPadding = element.style.paddingRight - const calculatedPadding = $(element).css('padding-right') - $(element) - .data('padding-right', actualPadding) - .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) - }) - - // Adjust sticky content margin - $(stickyContent).each((index, element) => { - const actualMargin = element.style.marginRight - const calculatedMargin = $(element).css('margin-right') - $(element) - .data('margin-right', actualMargin) - .css('margin-right', `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`) - }) - - // Adjust body padding - const actualPadding = document.body.style.paddingRight - const calculatedPadding = $(document.body).css('padding-right') - $(document.body) - .data('padding-right', actualPadding) - .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`) - } - - $(document.body).addClass(CLASS_NAME_OPEN) - } - - _resetScrollbar() { - // Restore fixed content padding - const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT)) - $(fixedContent).each((index, element) => { - const padding = $(element).data('padding-right') - $(element).removeData('padding-right') - // eslint-disable-next-line unicorn/prefer-logical-operator-over-ternary - element.style.paddingRight = padding ? padding : '' - }) - - // Restore sticky content - const elements = [].slice.call(document.querySelectorAll(`${SELECTOR_STICKY_CONTENT}`)) - $(elements).each((index, element) => { - const margin = $(element).data('margin-right') - if (typeof margin !== 'undefined') { - $(element).css('margin-right', margin).removeData('margin-right') - } - }) - - // Restore body padding - const padding = $(document.body).data('padding-right') - $(document.body).removeData('padding-right') - // eslint-disable-next-line unicorn/prefer-logical-operator-over-ternary - document.body.style.paddingRight = padding ? padding : '' - } - - _getScrollbarWidth() { // thx d.walsh - const scrollDiv = document.createElement('div') - scrollDiv.className = CLASS_NAME_SCROLLBAR_MEASURER - document.body.appendChild(scrollDiv) - const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth - document.body.removeChild(scrollDiv) - return scrollbarWidth - } - - // Static - static _jQueryInterface(config, relatedTarget) { - return this.each(function () { - let data = $(this).data(DATA_KEY) - const _config = { - ...Default, - ...$(this).data(), - ...(typeof config === 'object' && config ? config : {}) - } - - if (!data) { - data = new Modal(this, _config) - $(this).data(DATA_KEY, data) - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError(`No method named "${config}"`) - } - - data[config](relatedTarget) - } else if (_config.show) { - data.show(relatedTarget) - } - }) - } -} - -/** - * Data API implementation - */ - -$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { - let target - const selector = Util.getSelectorFromElement(this) - - if (selector) { - target = document.querySelector(selector) - } - - const config = $(target).data(DATA_KEY) ? - 'toggle' : { - ...$(target).data(), - ...$(this).data() - } - - if (this.tagName === 'A' || this.tagName === 'AREA') { - event.preventDefault() - } - - const $target = $(target).one(EVENT_SHOW, showEvent => { - if (showEvent.isDefaultPrevented()) { - // Only register focus restorer if modal will actually get shown - return - } - - $target.one(EVENT_HIDDEN, () => { - if ($(this).is(':visible')) { - this.focus() - } - }) - }) - - Modal._jQueryInterface.call($(target), config, this) -}) - -/** - * jQuery - */ - -$.fn[NAME] = Modal._jQueryInterface -$.fn[NAME].Constructor = Modal -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Modal._jQueryInterface -} - -export default Modal diff --git a/es-bs-base/js/src/popover.js b/es-bs-base/js/src/popover.js deleted file mode 100644 index 499b7e7b4..000000000 --- a/es-bs-base/js/src/popover.js +++ /dev/null @@ -1,172 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): popover.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' -import Tooltip from './tooltip' - -/** - * Constants - */ - -const NAME = 'popover' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.popover' -const EVENT_KEY = `.${DATA_KEY}` -const JQUERY_NO_CONFLICT = $.fn[NAME] -const CLASS_PREFIX = 'bs-popover' -const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g') - -const CLASS_NAME_FADE = 'fade' -const CLASS_NAME_SHOW = 'show' - -const SELECTOR_TITLE = '.popover-header' -const SELECTOR_CONTENT = '.popover-body' - -const Default = { - ...Tooltip.Default, - placement: 'right', - trigger: 'click', - content: '', - template: '' -} - -const DefaultType = { - ...Tooltip.DefaultType, - content: '(string|element|function)' -} - -const Event = { - HIDE: `hide${EVENT_KEY}`, - HIDDEN: `hidden${EVENT_KEY}`, - SHOW: `show${EVENT_KEY}`, - SHOWN: `shown${EVENT_KEY}`, - INSERTED: `inserted${EVENT_KEY}`, - CLICK: `click${EVENT_KEY}`, - FOCUSIN: `focusin${EVENT_KEY}`, - FOCUSOUT: `focusout${EVENT_KEY}`, - MOUSEENTER: `mouseenter${EVENT_KEY}`, - MOUSELEAVE: `mouseleave${EVENT_KEY}` -} - -/** - * Class definition - */ - -class Popover extends Tooltip { - // Getters - static get VERSION() { - return VERSION - } - - static get Default() { - return Default - } - - static get NAME() { - return NAME - } - - static get DATA_KEY() { - return DATA_KEY - } - - static get Event() { - return Event - } - - static get EVENT_KEY() { - return EVENT_KEY - } - - static get DefaultType() { - return DefaultType - } - - // Overrides - isWithContent() { - return this.getTitle() || this._getContent() - } - - addAttachmentClass(attachment) { - $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`) - } - - getTipElement() { - this.tip = this.tip || $(this.config.template)[0] - return this.tip - } - - setContent() { - const $tip = $(this.getTipElement()) - - // We use append for html objects to maintain js events - this.setElementContent($tip.find(SELECTOR_TITLE), this.getTitle()) - let content = this._getContent() - if (typeof content === 'function') { - content = content.call(this.element) - } - - this.setElementContent($tip.find(SELECTOR_CONTENT), content) - - $tip.removeClass(`${CLASS_NAME_FADE} ${CLASS_NAME_SHOW}`) - } - - // Private - _getContent() { - return this.element.getAttribute('data-content') || - this.config.content - } - - _cleanTipClass() { - const $tip = $(this.getTipElement()) - const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX) - if (tabClass !== null && tabClass.length > 0) { - $tip.removeClass(tabClass.join('')) - } - } - - // Static - static _jQueryInterface(config) { - return this.each(function () { - let data = $(this).data(DATA_KEY) - const _config = typeof config === 'object' ? config : null - - if (!data && /dispose|hide/.test(config)) { - return - } - - if (!data) { - data = new Popover(this, _config) - $(this).data(DATA_KEY, data) - } - - if (typeof config === 'string') { - if (typeof data[config] === 'undefined') { - throw new TypeError(`No method named "${config}"`) - } - - data[config]() - } - }) - } -} - -/** - * jQuery - */ - -$.fn[NAME] = Popover._jQueryInterface -$.fn[NAME].Constructor = Popover -$.fn[NAME].noConflict = () => { - $.fn[NAME] = JQUERY_NO_CONFLICT - return Popover._jQueryInterface -} - -export default Popover diff --git a/es-bs-base/js/src/scrollspy.js b/es-bs-base/js/src/scrollspy.js deleted file mode 100644 index fb53db666..000000000 --- a/es-bs-base/js/src/scrollspy.js +++ /dev/null @@ -1,313 +0,0 @@ -/** - * -------------------------------------------------------------------------- - * Bootstrap (v4.6.1): scrollspy.js - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - * -------------------------------------------------------------------------- - */ - -import $ from 'jquery' -import Util from './util' - -/** - * Constants - */ - -const NAME = 'scrollspy' -const VERSION = '4.6.1' -const DATA_KEY = 'bs.scrollspy' -const EVENT_KEY = `.${DATA_KEY}` -const DATA_API_KEY = '.data-api' -const JQUERY_NO_CONFLICT = $.fn[NAME] - -const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item' -const CLASS_NAME_ACTIVE = 'active' - -const EVENT_ACTIVATE = `activate${EVENT_KEY}` -const EVENT_SCROLL = `scroll${EVENT_KEY}` -const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}` - -const METHOD_OFFSET = 'offset' -const METHOD_POSITION = 'position' - -const SELECTOR_DATA_SPY = '[data-spy="scroll"]' -const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group' -const SELECTOR_NAV_LINKS = '.nav-link' -const SELECTOR_NAV_ITEMS = '.nav-item' -const SELECTOR_LIST_ITEMS = '.list-group-item' -const SELECTOR_DROPDOWN = '.dropdown' -const SELECTOR_DROPDOWN_ITEMS = '.dropdown-item' -const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle' - -const Default = { - offset: 10, - method: 'auto', - target: '' -} - -const DefaultType = { - offset: 'number', - method: 'string', - target: '(string|element)' -} - -/** - * Class definition - */ - -class ScrollSpy { - constructor(element, config) { - this._element = element - this._scrollElement = element.tagName === 'BODY' ? window : element - this._config = this._getConfig(config) - this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS},` + - `${this._config.target} ${SELECTOR_LIST_ITEMS},` + - `${this._config.target} ${SELECTOR_DROPDOWN_ITEMS}` - this._offsets = [] - this._targets = [] - this._activeTarget = null - this._scrollHeight = 0 - - $(this._scrollElement).on(EVENT_SCROLL, event => this._process(event)) - - this.refresh() - this._process() - } - - // Getters - static get VERSION() { - return VERSION - } - - static get Default() { - return Default - } - - // Public - refresh() { - const autoMethod = this._scrollElement === this._scrollElement.window ? - METHOD_OFFSET : METHOD_POSITION - - const offsetMethod = this._config.method === 'auto' ? - autoMethod : this._config.method - - const offsetBase = offsetMethod === METHOD_POSITION ? - this._getScrollTop() : 0 - - this._offsets = [] - this._targets = [] - - this._scrollHeight = this._getScrollHeight() - - const targets = [].slice.call(document.querySelectorAll(this._selector)) - - targets - .map(element => { - let target - const targetSelector = Util.getSelectorFromElement(element) - - if (targetSelector) { - target = document.querySelector(targetSelector) - } - - if (target) { - const targetBCR = target.getBoundingClientRect() - if (targetBCR.width || targetBCR.height) { - // eslint-disable-next-line no-warning-comments - // TODO: remove sketch reliance on jQuery position/offset - return [ - $(target)[offsetMethod]().top + offsetBase, - targetSelector - ] - } - } - - return null - }) - .filter(Boolean) - .sort((a, b) => a[0] - b[0]) - .forEach(item => { - this._offsets.push(item[0]) - this._targets.push(item[1]) - }) - } - - dispose() { - $.removeData(this._element, DATA_KEY) - $(this._scrollElement).off(EVENT_KEY) - - this._element = null - this._scrollElement = null - this._config = null - this._selector = null - this._offsets = null - this._targets = null - this._activeTarget = null - this._scrollHeight = null - } - - // Private - _getConfig(config) { - config = { - ...Default, - ...(typeof config === 'object' && config ? config : {}) - } - - if (typeof config.target !== 'string' && Util.isElement(config.target)) { - let id = $(config.target).attr('id') - if (!id) { - id = Util.getUID(NAME) - $(config.target).attr('id', id) - } - - config.target = `#${id}` - } - - Util.typeCheckConfig(NAME, config, DefaultType) - - return config - } - - _getScrollTop() { - return this._scrollElement === window ? - this._scrollElement.pageYOffset : this._scrollElement.scrollTop - } - - _getScrollHeight() { - return this._scrollElement.scrollHeight || Math.max( - document.body.scrollHeight, - document.documentElement.scrollHeight - ) - } - - _getOffsetHeight() { - return this._scrollElement === window ? - window.innerHeight : this._scrollElement.getBoundingClientRect().height - } - - _process() { - const scrollTop = this._getScrollTop() + this._config.offset - const scrollHeight = this._getScrollHeight() - const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight() - - if (this._scrollHeight !== scrollHeight) { - this.refresh() - } - - if (scrollTop >= maxScroll) { - const target = this._targets[this._targets.length - 1] - - if (this._activeTarget !== target) { - this._activate(target) - } - - return - } - - if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { - this._activeTarget = null - this._clear() - return - } - - for (let i = this._offsets.length; i--;) { - const isActiveTarget = this._activeTarget !== this._targets[i] && - scrollTop >= this._offsets[i] && - (typeof this._offsets[i + 1] === 'undefined' || - scrollTop < this._offsets[i + 1]) - - if (isActiveTarget) { - this._activate(this._targets[i]) - } - } - } - - _activate(target) { - this._activeTarget = target - - this._clear() - - const queries = this._selector - .split(',') - .map(selector => `${selector}[data-target="${target}"],${selector}[href="${target}"]`) - - const $link = $([].slice.call(document.querySelectorAll(queries.join(',')))) - - if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) { - $link.closest(SELECTOR_DROPDOWN) - .find(SELECTOR_DROPDOWN_TOGGLE) - .addClass(CLASS_NAME_ACTIVE) - $link.addClass(CLASS_NAME_ACTIVE) - } else { - // Set triggered link as active - $link.addClass(CLASS_NAME_ACTIVE) - // Set triggered links parents as active - // With both ' - - var $dropdown = $(dropdownHTML) - .appendTo('#qunit-fixture') - .find('[data-toggle="dropdown"]') - .bootstrapDropdown() - - var $textarea = $('#textarea') - - $dropdown - .parent('.dropdown') - .one('shown.bs.dropdown', function () { - assert.ok(true, 'shown was fired') - - // Key space - $textarea.trigger('focus').trigger($.Event('keydown', { - which: 32 - })) - assert.true($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is shown') - assert.true($(document.activeElement).is($textarea), 'textarea is still focused') - - // Key escape - $textarea.trigger('focus').trigger($.Event('keydown', { - which: 27 - })) - assert.false($dropdown.parent('.dropdown').hasClass('show'), 'dropdown menu is not shown') - - $dropdown - .parent('.dropdown') - .one('shown.bs.dropdown', function () { - // Key down - $textarea.trigger('focus').trigger($.Event('keydown', { - which: 40 - })) - assert.strictEqual(document.activeElement, $('#item1')[0], 'item1 is focused') - - $dropdown - .parent('.dropdown') - .one('shown.bs.dropdown', function () { - // Key up - $textarea.trigger('focus').trigger($.Event('keydown', { - which: 38 - })) - assert.strictEqual(document.activeElement, $('#item1')[0], 'item1 is focused') - done() - }).bootstrapDropdown('toggle') - $textarea.trigger('click') - }) - $textarea.trigger('click') - }) - $textarea.trigger('click') - }) - - QUnit.test('should not stop key event propagation when dropdown is disabled', function (assert) { - assert.expect(1) - var done = assert.async() - - var dropdownHTML = '
' + - '' - - var $dropdown = $(dropdownHTML) - .appendTo('#qunit-fixture') - .find('[data-toggle="dropdown"]') - .bootstrapDropdown() - - var $body = $('body') - - $(document).on('keydown', function () { - $body.addClass('event-handled') - }) - - // Key escape - $dropdown.trigger('focus').trigger($.Event('keydown', { - which: 27 - })) - - assert.true($body.hasClass('event-handled'), 'ESC key event was propagated') - done() - }) - - QUnit.test('should not stop ESC key event propagation when dropdown is not active', function (assert) { - assert.expect(1) - var done = assert.async() - - var dropdownHTML = '
' + - '' - - var $dropdown = $(dropdownHTML) - .appendTo('#qunit-fixture') - .find('[data-toggle="dropdown"]') - .bootstrapDropdown() - - var $body = $('body') - - $(document).on('keydown', function () { - $body.addClass('event-handled') - }) - - // Key escape - $dropdown.trigger('focus').trigger($.Event('keydown', { - which: 27 - })) - - assert.true($body.hasClass('event-handled'), 'ESC key event was propagated') - done() - }) - - QUnit.test('should not use Popper if display set to static', function (assert) { - assert.expect(1) - var dropdownHTML = - '