diff --git a/.babelrc.js b/.babelrc.js index 44a509954105..1d6404edbe5f 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -1,17 +1,14 @@ module.exports = { presets: [ [ - '@babel/env', + '@babel/preset-env', { loose: true, - modules: false, - exclude: ['transform-typeof-symbol'] + bugfixes: true, + modules: false } ] ], - plugins: [ - '@babel/plugin-proposal-object-rest-spread' - ], env: { test: { plugins: [ 'istanbul' ] diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json new file mode 100644 index 000000000000..0576af92f564 --- /dev/null +++ b/.bundlewatch.config.json @@ -0,0 +1,50 @@ +{ + "files": [ + { + "path": "./dist/css/bootstrap-grid.css", + "maxSize": "7 kB" + }, + { + "path": "./dist/css/bootstrap-grid.min.css", + "maxSize": "6.25 kB" + }, + { + "path": "./dist/css/bootstrap-reboot.css", + "maxSize": "2 kB" + }, + { + "path": "./dist/css/bootstrap-reboot.min.css", + "maxSize": "2 kB" + }, + { + "path": "./dist/css/bootstrap.css", + "maxSize": "26 kB" + }, + { + "path": "./dist/css/bootstrap.min.css", + "maxSize": "23.75 kB" + }, + { + "path": "./dist/js/bootstrap.bundle.js", + "maxSize": "48 kB" + }, + { + "path": "./dist/js/bootstrap.bundle.min.js", + "maxSize": "21.75 kB" + }, + { + "path": "./dist/js/bootstrap.js", + "maxSize": "25.5 kB" + }, + { + "path": "./dist/js/bootstrap.min.js", + "maxSize": "15 kB" + } + ], + "ci": { + "trackBranches": [ + "main", + "v4-dev" + ] + } +} diff --git a/.eslintignore b/.eslintignore index 96958b2ba864..a18b03a5df54 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,6 @@ **/*.min.js **/dist/ **/vendor/ -/_gh_pages/ +/_site/ +/js/coverage/ +/site/static/sw.js diff --git a/.eslintrc.json b/.eslintrc.json index bfd2d333ae60..3d099fc9de80 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,233 +1,76 @@ { "root": true, - "parser": "babel-eslint", - "env": { - "browser": true, - "es6": true - }, - "extends": ["eslint:recommended"], + "extends": [ + "plugin:import/errors", + "plugin:import/warnings", + "plugin:unicorn/recommended", + "xo", + "xo/browser" + ], "rules": { - // Possible Errors - "no-await-in-loop": "error", - "no-extra-parens": "error", - "no-prototype-builtins": "error", - "no-template-curly-in-string": "error", - "valid-jsdoc": "error", - - // Best Practices - "accessor-pairs": "error", - "array-callback-return": "error", - "block-scoped-var": "error", - "class-methods-use-this": "off", - "complexity": "error", - "consistent-return": "error", - "curly": "error", - "default-case": "error", - "dot-location": ["error", "property"], - "dot-notation": "error", - "eqeqeq": "error", - "guard-for-in": "error", - "no-alert": "error", - "no-caller": "error", - "no-div-regex": "error", - "no-else-return": "error", - "no-empty-function": "error", - "no-eq-null": "error", - "no-eval": "error", - "no-extend-native": "error", - "no-extra-bind": "error", - "no-extra-label": "error", - "no-floating-decimal": "error", - "no-implicit-coercion": "error", - "no-implicit-globals": "error", - "no-implied-eval": "error", - "no-invalid-this": "off", - "no-iterator": "error", - "no-labels": "error", - "no-lone-blocks": "error", - "no-loop-func": "error", - "no-magic-numbers": ["error", { - "ignore": [-1, 0, 1], - "ignoreArrayIndexes": true + "arrow-body-style": "off", + "capitalized-comments": "off", + "comma-dangle": [ + "error", + "never" + ], + "indent": [ + "error", + 2, + { + "MemberExpression": "off", + "SwitchCase": 1 } ], - "no-multi-spaces": ["error", { - "ignoreEOLComments": true, - "exceptions": { - "AssignmentExpression": true, - "ArrowFunctionExpression": true, - "CallExpression": true, - "VariableDeclarator": true - } + "max-params": [ + "warn", + 5 + ], + "new-cap": [ + "error", + { + "properties": false } ], - "no-multi-str": "error", - "no-new": "error", - "no-new-func": "error", - "no-new-wrappers": "error", - "no-octal-escape": "error", - "no-param-reassign": "off", - "no-proto": "error", - "no-restricted-properties": "error", - "no-return-assign": "error", - "no-return-await": "error", - "no-script-url": "error", - "no-self-compare": "error", - "no-sequences": "error", - "no-throw-literal": "error", - "no-unmodified-loop-condition": "error", - "no-unused-expressions": "error", - "no-useless-call": "error", - "no-useless-concat": "error", - "no-useless-return": "error", - "no-void": "error", - "no-warning-comments": "off", - "no-with": "error", - "prefer-promise-reject-errors": "error", - "radix": "error", - "require-await": "error", - "vars-on-top": "error", - "wrap-iife": "error", - "yoda": "error", - - // Strict Mode - "strict": "error", - - // Variables - "init-declarations": "off", - "no-catch-shadow": "error", - "no-label-var": "error", - "no-restricted-globals": "error", - "no-shadow": "off", - "no-shadow-restricted-names": "error", - "no-undef-init": "error", - "no-undefined": "error", - "no-use-before-define": "off", - - // Node.js and CommonJS - "callback-return": "off", - "global-require": "error", - "handle-callback-err": "error", - "no-mixed-requires": "error", - "no-new-require": "error", - "no-path-concat": "error", - "no-process-env": "error", - "no-process-exit": "error", - "no-restricted-modules": "error", - "no-sync": "error", - - // Stylistic Issues - "array-bracket-spacing": "error", - "block-spacing": "error", - "brace-style": "error", - "camelcase": "error", - "capitalized-comments": "off", - "comma-dangle": "error", - "comma-spacing": "error", - "comma-style": "error", - "computed-property-spacing": "error", - "consistent-this": "error", - "eol-last": "error", - "func-call-spacing": "error", - "func-name-matching": "error", - "func-names": "off", - "func-style": ["error", "declaration"], - "id-blacklist": "error", - "id-length": "off", - "id-match": "error", - "indent": ["error", 2, { "SwitchCase": 1 }], - "jsx-quotes": "error", - "key-spacing": "off", - "keyword-spacing": "error", - "linebreak-style": ["error", "unix"], - "line-comment-position": "off", - "lines-around-comment": "off", - "lines-around-directive": "error", - "max-depth": ["error", 10], - "max-len": "off", - "max-lines": "off", - "max-nested-callbacks": "error", - "max-params": "off", - "max-statements": "off", - "max-statements-per-line": "error", - "multiline-ternary": "off", - "new-cap": ["error", { "capIsNewExceptionPattern": "$.*" }], - "newline-after-var": "off", - "newline-per-chained-call": ["error", { "ignoreChainWithDepth": 5 }], - "new-parens": "error", - "no-array-constructor": "error", - "no-bitwise": "error", - "no-continue": "off", - "no-inline-comments": "off", - "no-lonely-if": "error", + "no-console": "error", "no-mixed-operators": "off", - "no-multi-assign": "error", - "no-multiple-empty-lines": "error", - "nonblock-statement-body-position": "error", "no-negated-condition": "off", - "no-nested-ternary": "error", - "no-new-object": "error", - "no-plusplus": "off", - "no-restricted-syntax": "error", - "no-tabs": "error", - "no-ternary": "off", - "no-trailing-spaces": "error", - "no-underscore-dangle": "off", - "no-unneeded-ternary": "error", - "no-whitespace-before-property": "error", - "object-curly-newline": ["error", { "minProperties": 1 }], - "object-curly-spacing": ["error", "always"], - "object-property-newline": "error", - "one-var": ["error", "never"], - "one-var-declaration-per-line": "error", - "operator-assignment": "error", - "operator-linebreak": "error", - "padded-blocks": ["error", "never"], - "padding-line-between-statements": "off", - "quote-props": ["error", "as-needed"], - "quotes": ["error", "single"], - "require-jsdoc": "off", - "semi": ["error", "never"], - "semi-spacing": "error", - "sort-keys": "off", - "sort-vars": "error", - "space-before-blocks": "error", - "space-before-function-paren": ["error", { - "anonymous": "always", - "named": "never" - }], - "space-in-parens": "error", - "space-infix-ops": "error", - "space-unary-ops": "error", - "spaced-comment": "error", - "template-tag-spacing": "error", - "unicode-bom": "error", - "wrap-regex": "off", - - // ECMAScript 6 - "arrow-body-style": ["error", "as-needed"], - "arrow-parens": "error", - "arrow-spacing": "error", - "generator-star-spacing": "error", - "no-confusing-arrow": "error", - "no-duplicate-imports": "error", - "no-restricted-imports": "error", - "no-useless-computed-key": "error", - "no-useless-constructor": "error", - "no-useless-rename": "error", - "no-var": "error", - "object-shorthand": "error", - "prefer-arrow-callback": "error", - "prefer-const": "error", - "prefer-destructuring": "off", - "prefer-numeric-literals": "error", - "prefer-rest-params": "error", - "prefer-spread": "error", - "prefer-template": "error", - "rest-spread-spacing": "error", - "sort-imports": "error", - "symbol-description": "error", - "template-curly-spacing": "error", - "yield-star-spacing": "error" + "object-curly-spacing": [ + "error", + "always" + ], + "operator-linebreak": [ + "error", + "after" + ], + "semi": [ + "error", + "never" + ], + "unicorn/consistent-function-scoping": "off", + "unicorn/explicit-length-check": "off", + "unicorn/no-array-callback-reference": "off", + "unicorn/no-array-for-each": "off", + "unicorn/no-array-method-this-argument": "off", + "unicorn/no-for-loop": "off", + "unicorn/no-null": "off", + "unicorn/no-unused-properties": "error", + "unicorn/no-useless-undefined": "off", + "unicorn/numeric-separators-style": "off", + "unicorn/prefer-array-find": "off", + "unicorn/prefer-array-flat": "off", + "unicorn/prefer-dom-node-append": "off", + "unicorn/prefer-dom-node-dataset": "off", + "unicorn/prefer-dom-node-remove": "off", + "unicorn/prefer-includes": "off", + "unicorn/prefer-math-trunc": "off", + "unicorn/prefer-module": "off", + "unicorn/prefer-number-properties": "off", + "unicorn/prefer-optional-catch-binding": "off", + "unicorn/prefer-prototype-methods": "off", + "unicorn/prefer-query-selector": "off", + "unicorn/prefer-reflect-apply": "off", + "unicorn/prefer-set-has": "off", + "unicorn/prevent-abbreviations": "off" } } diff --git a/.gitattributes b/.gitattributes index 39813c758947..40b1c37421a0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,18 +1,8 @@ # Enforce Unix newlines -*.css text eol=lf -*.html text eol=lf -*.js text eol=lf -*.json text eol=lf -*.md text eol=lf -*.rb text eol=lf -*.scss text eol=lf -*.svg text eol=lf -*.txt text eol=lf -*.xml text eol=lf -*.yml text eol=lf +* text=auto eol=lf # Don't diff or textually merge source maps -*.map binary +*.map binary bootstrap.css linguist-vendored=false bootstrap.js linguist-vendored=false diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f579111bd41a..c4de33669396 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -18,8 +18,9 @@ the preferred channel for [bug reports](#bug-reports), [features requests](#feat and [submitting pull requests](#pull-requests), but please respect the following restrictions: -* Please **do not** use the issue tracker for personal support requests. Stack - Overflow ([`bootstrap-4`](https://stackoverflow.com/questions/tagged/bootstrap-4) tag), [Slack](https://bootstrap-slack.herokuapp.com/) or [IRC](README.md#community) are better places to get help. +* Please **do not** use the issue tracker for personal support requests. Stack + Overflow ([`bootstrap-4`](https://stackoverflow.com/questions/tagged/bootstrap-4) tag), + [Slack](https://bootstrap-slack.herokuapp.com/) or [IRC](/README.md#community) are better places to get help. * Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others. @@ -57,15 +58,14 @@ Good bug reports are extremely helpful, so thanks! Guidelines for bug reports: -0. **Validate and lint your code** — [validate your HTML](https://html5.validator.nu/) - and [lint your HTML](https://github.com/twbs/bootlint) to ensure your +0. **[validate your HTML](https://html5.validator.nu/)** to ensure your problem isn't caused by a simple error in your own code. 1. **Use the GitHub issue search** — check if the issue has already been reported. 2. **Check if the issue has been fixed** — try to reproduce it using the - latest `master` or development branch in the repository. + latest `master` or `v4-dev` branch in the repository. 3. **Isolate the problem** — ideally create a [reduced test case](https://css-tricks.com/reduced-test-cases/) and a live example. @@ -102,16 +102,12 @@ Example: Sometimes bugs reported to us are actually caused by bugs in the browser(s) themselves, not bugs in Bootstrap per se. When feasible, we aim to report such upstream bugs to the relevant browser vendor(s), and then list them on our [Wall of Browser Bugs](https://getbootstrap.com/browser-bugs/) and [document them in MDN](https://developer.mozilla.org/en-US/docs/Web). -| Vendor(s) | Browser(s) | Rendering engine | Bug reporting website(s) | Notes | -| ------------- | ---------------------------- | ---------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------- | -| Mozilla | Firefox | Gecko | https://bugzilla.mozilla.org/enter_bug.cgi | "Core" is normally the right product option to choose. | -| Apple | Safari | WebKit | https://bugs.webkit.org/enter_bug.cgi?product=WebKit
https://bugreport.apple.com/ | In Apple's bug reporter, choose "Safari" as the product. | -| Google, Opera | Chrome, Chromium, Opera v15+ | Blink | https://bugs.chromium.org/p/chromium/issues/list | Click the "New issue" button. | -| Microsoft | Edge | EdgeHTML | https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/ | | - -### Issues bots - -[@twbs-lmvtfy](https://github.com/twbs-lmvtfy) is a Bootstrap bot that hangs out in our GitHub issue tracker and automatically checks for HTML validation errors in live examples (e.g. jsFiddles, JS Bins, Bootplys, Plunks, CodePens, etc.) posted in issue comments. If it finds any errors, it will post a follow-up comment on the issue and point out the errors. If this happens with an example you've posted, please fix the errors and post an updated live example. If you opened a bug report, please check whether the bug still occurs with your revised, valid live example. If the bug no longer occurs, it was probably due to your invalid HTML rather than something in Bootstrap and we'd appreciate it if you could close out the GitHub issue. +| Vendor(s) | Browser(s) | Rendering engine | Bug reporting website(s) | Notes | +| ------------- | ---------------------------- | ---------------- | ------------------------------------------------------ | -------------------------------------------------------- | +| Mozilla | Firefox | Gecko | https://bugzilla.mozilla.org/enter_bug.cgi | "Core" is normally the right product option to choose. | +| Apple | Safari | WebKit | https://bugs.webkit.org/enter_bug.cgi?product=WebKit | In Apple's bug reporter, choose "Safari" as the product. | +| Google, Opera | Chrome, Chromium, Opera v15+ | Blink | https://bugs.chromium.org/p/chromium/issues/list | Click the "New issue" button. | +| Microsoft | Edge | Blink | https://developer.microsoft.com/en-us/microsoft-edge/ | Go to "Help > Send Feedback" from the browser | ## Feature requests @@ -128,23 +124,25 @@ Good pull requests—patches, improvements, new features—are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. -**Please ask first** before embarking on any significant pull request (e.g. +**Please ask first** before embarking on any **significant** pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the -project's developers might not want to merge into the project. +project's developers might not want to merge into the project. For trivial +things, or things that don't require a lot of your time, you can go ahead and +make a PR. Please adhere to the [coding guidelines](#code-guidelines) used throughout the project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). -**Do not edit `bootstrap.css`, or `bootstrap.js` -directly!** Those files are automatically generated. You should edit the -source files in [`/bootstrap/scss/`](https://github.com/twbs/bootstrap/tree/master/scss) -and/or [`/bootstrap/js/`](https://github.com/twbs/bootstrap/tree/master/js) instead. +**Do not edit `bootstrap.css` or `bootstrap.js`, and do not commit +any dist files (`dist/` or `js/dist`).** Those files are automatically generated by our build tools. You should +edit the source files in [`/bootstrap/scss/`](https://github.com/twbs/bootstrap/tree/v4-dev/scss) +and/or [`/bootstrap/js/src/`](https://github.com/twbs/bootstrap/tree/v4-dev/js/src) instead. Similarly, when contributing to Bootstrap's documentation, you should edit the documentation source files in -[the `/bootstrap/docs/` directory of the `master` branch](https://github.com/twbs/bootstrap/tree/master/docs). +[the `/bootstrap/site/content/docs/` directory of the `v4-dev` branch](https://github.com/twbs/bootstrap/tree/v4-dev/site/content/docs). **Do not edit the `gh-pages` branch.** That branch is generated from the documentation source files and is managed separately by the Bootstrap Core Team. @@ -166,8 +164,8 @@ included in the project: 2. If you cloned a while ago, get the latest changes from upstream: ```bash - git checkout master - git pull upstream master + git checkout v4-dev + git pull upstream v4-dev ``` 3. Create a new topic branch (off the main project development branch) to @@ -186,7 +184,7 @@ included in the project: 5. Locally merge (or rebase) the upstream development branch into your topic branch: ```bash - git pull [--rebase] upstream master + git pull [--rebase] upstream v4-dev ``` 6. Push your topic branch up to your fork: @@ -196,12 +194,12 @@ included in the project: ``` 7. [Open a Pull Request](https://help.github.com/articles/about-pull-requests/) - with a clear title and description against the `master` branch. + with a clear title and description against the `v4-dev` branch. **IMPORTANT**: By submitting a patch, you agree to allow the project owners to -license your work under the terms of the [MIT License](LICENSE) (if it +license your work under the terms of the [MIT License](../LICENSE) (if it includes code changes) and under the terms of the -[Creative Commons Attribution 3.0 Unported License](docs/LICENSE) +[Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/) (if it includes documentation changes). @@ -209,7 +207,7 @@ includes code changes) and under the terms of the ### HTML -[Adhere to the Code Guide.](http://codeguide.co/#html) +[Adhere to the Code Guide.](https://codeguide.co/#html) - Use tags and elements appropriate for an HTML5 doctype (e.g., self-closing tags). - Use CDNs and HTTPS for third-party JS when possible. We don't use protocol-relative URLs in this case because they break when viewing the page locally via `file://`. @@ -217,10 +215,10 @@ includes code changes) and under the terms of the ### CSS -[Adhere to the Code Guide.](http://codeguide.co/#css) +[Adhere to the Code Guide.](https://codeguide.co/#css) - When feasible, default color palettes should comply with [WCAG color contrast guidelines](https://www.w3.org/TR/WCAG20/#visual-audio-contrast). -- Except in rare cases, don't remove default `:focus` styles (via e.g. `outline: none;`) without providing alternative styles. See [this A11Y Project post](https://a11yproject.com/posts/never-remove-css-outlines/) for more details. +- Except in rare cases, don't remove default `:focus` styles (via e.g. `outline: none;`) without providing alternative styles. See [this A11Y Project post](https://www.a11yproject.com/posts/2013-01-25-never-remove-css-outlines/) for more details. ### JS @@ -237,7 +235,7 @@ Run `npm run test` before committing to ensure your changes follow our coding st ## License -By contributing your code, you agree to license your contribution under the [MIT License](LICENSE). -By contributing to the documentation, you agree to license your contribution under the [Creative Commons Attribution 3.0 Unported License](docs/LICENSE). +By contributing your code, you agree to license your contribution under the [MIT License](../LICENSE). +By contributing to the documentation, you agree to license your contribution under the [Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/). Prior to v3.1.0, Bootstrap's code was released under the Apache License v2.0. diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md deleted file mode 100644 index 8e1285515d00..000000000000 --- a/.github/ISSUE_TEMPLATE/bug.md +++ /dev/null @@ -1,11 +0,0 @@ -Before opening: - -- [Search for duplicate or closed issues](https://github.com/twbs/bootstrap/issues?utf8=%E2%9C%93&q=is%3Aissue) -- [Validate](https://html5.validator.nu/) and [lint](https://github.com/twbs/bootlint#in-the-browser) any HTML to avoid common problems -- Read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md) - -Bug reports must include: - -- Operating system and version (Windows, macOS, Android, iOS, Win10 Mobile) -- Browser and version (Chrome, Firefox, Safari, IE, MS Edge, Opera 15+, Android Browser) -- [Reduced test case](https://css-tricks.com/reduced-test-cases/) and suggested fix using [CodePen](https://codepen.io/) or [JS Bin](https://jsbin.com/) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ab363e0cac6c..4899d4de20a3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,17 +1,20 @@ --- name: Bug report about: Tell us about a bug you may have identified in Bootstrap. +title: '' +labels: '' +assignees: '' --- Before opening: - [Search for duplicate or closed issues](https://github.com/twbs/bootstrap/issues?utf8=%E2%9C%93&q=is%3Aissue) -- [Validate](https://html5.validator.nu/) and [lint](https://github.com/twbs/bootlint#in-the-browser) any HTML to avoid common problems -- Read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md) +- [Validate](https://html5.validator.nu/) any HTML to avoid common problems +- Read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/v4-dev/.github/CONTRIBUTING.md) Bug reports must include: -- Operating system and version (Windows, macOS, Android, iOS, Win10 Mobile) -- Browser and version (Chrome, Firefox, Safari, IE, MS Edge, Opera 15+, Android Browser) -- [Reduced test case](https://css-tricks.com/reduced-test-cases/) and suggested fix using [CodePen](https://codepen.io/) or [JS Bin](https://jsbin.com/) +- Operating system and version (Windows, macOS, Android, iOS) +- Browser and version (Chrome, Firefox, Safari, Internet Explorer, Microsoft Edge, Opera, Android Browser) +- A [reduced test case](https://css-tricks.com/reduced-test-cases/) or suggested fix using [CodePen](https://codepen.io/) or [JS Bin](https://jsbin.com/) diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md deleted file mode 100644 index 4f866e2141e9..000000000000 --- a/.github/ISSUE_TEMPLATE/feature.md +++ /dev/null @@ -1,9 +0,0 @@ -Before opening: - -- [Search for duplicate or closed issues](https://github.com/twbs/bootstrap/issues?utf8=%E2%9C%93&q=is%3Aissue) -- Read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md) - -Feature requests must include: - -- As much detail as possible for what we should add and why it's important to Bootstrap -- Relevant links to prior art, screenshots, or live demos whenever possible diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 389bd4345ae8..db44076d91f2 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,13 +1,16 @@ --- name: Feature request about: Suggest an idea for a new feature in Bootstrap. +title: '' +labels: feature +assignees: '' --- Before opening: - [Search for duplicate or closed issues](https://github.com/twbs/bootstrap/issues?utf8=%E2%9C%93&q=is%3Aissue) -- Read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md) +- Read the [contributing guidelines](https://github.com/twbs/bootstrap/blob/v4-dev/.github/CONTRIBUTING.md) Feature requests must include: diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md index de3c4b552e9a..f54f4170dd15 100644 --- a/.github/SUPPORT.md +++ b/.github/SUPPORT.md @@ -7,5 +7,5 @@ See the [contributing guidelines](CONTRIBUTING.md) for sharing bug reports. For general troubleshooting or help getting started: - Join [the official Slack room](https://bootstrap-slack.herokuapp.com/). -- Chat with fellow Bootstrappers in IRC. On the `irc.freenode.net` server, in the `##bootstrap` channel. +- Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel. - Ask and explore Stack Overflow with the [`bootstrap-4`](https://stackoverflow.com/questions/tagged/bootstrap-4) tag. diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml new file mode 100644 index 000000000000..03be3f76d69e --- /dev/null +++ b/.github/workflows/browserstack.yml @@ -0,0 +1,37 @@ +name: BrowserStack + +on: + push: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + NODE: 16 + +jobs: + browserstack: + runs-on: ubuntu-latest + if: github.repository == 'twbs/bootstrap' && (!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')) + timeout-minutes: 30 + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ env.NODE }}" + cache: npm + + - name: Install npm dependencies + run: npm ci + + - name: Run dist + run: npm run dist + + - name: Run BrowserStack tests + run: npm run js-test-cloud + env: + BROWSER_STACK_ACCESS_KEY: "${{ secrets.BROWSER_STACK_ACCESS_KEY }}" + BROWSER_STACK_USERNAME: "${{ secrets.BROWSER_STACK_USERNAME }}" diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml new file mode 100644 index 000000000000..70c8a575e590 --- /dev/null +++ b/.github/workflows/bundlewatch.yml @@ -0,0 +1,38 @@ +name: Bundlewatch + +on: + push: + branches-ignore: + - "dependabot/**" + pull_request: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + NODE: 16 + +jobs: + bundlewatch: + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ env.NODE }}" + cache: npm + + - name: Install npm dependencies + run: npm ci + + - name: Run dist + run: npm run dist + + - name: Run bundlewatch + run: npm run bundlewatch + env: + BUNDLEWATCH_GITHUB_TOKEN: "${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }}" + CI_BRANCH_BASE: v4-dev diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000000..70be0563c91e --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,38 @@ +name: "CodeQL" + +on: + push: + branches: + - main + - v4-dev + - "!dependabot/**" + pull_request: + # The branches below must be a subset of the branches above + branches: + - main + - v4-dev + - "!dependabot/**" + schedule: + - cron: "0 2 * * 5" + workflow_dispatch: + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: "javascript" + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/css.yml b/.github/workflows/css.yml new file mode 100644 index 000000000000..857a5672cb35 --- /dev/null +++ b/.github/workflows/css.yml @@ -0,0 +1,32 @@ +name: CSS + +on: + push: + branches-ignore: + - "dependabot/**" + pull_request: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + NODE: 16 + +jobs: + css: + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ env.NODE }}" + cache: npm + + - name: Install npm dependencies + run: npm ci + + - name: Build CSS + run: npm run css diff --git a/.github/workflows/dart-sass.yml b/.github/workflows/dart-sass.yml new file mode 100644 index 000000000000..1b74bb5304ad --- /dev/null +++ b/.github/workflows/dart-sass.yml @@ -0,0 +1,31 @@ +name: CSS (Dart Sass) + +on: + push: + branches-ignore: + - "dependabot/**" + pull_request: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + NODE: 16 + +jobs: + css: + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ env.NODE }}" + + - name: Build CSS with Dart Sass + run: | + npx --package sass@latest sass --version + npx --package sass@latest sass --style expanded --source-map --embed-sources --no-error-css scss/:dist-sass/css/ + ls -Al dist-sass/css diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000000..f33413eb4b93 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,45 @@ +name: Docs + +on: + push: + branches-ignore: + - "dependabot/**" + pull_request: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + NODE: 16 + +jobs: + docs: + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ env.NODE }}" + cache: npm + + - run: java -version + + - name: Install npm dependencies + run: npm ci + + - name: Build docs + run: npm run docs-build + + - name: Validate HTML + run: npm run docs-vnu + + - name: Run linkinator + uses: JustinBeckwith/linkinator-action@v1 + with: + paths: _site + recurse: true + verbosity: error + skip: "^(?!http://localhost)" diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml new file mode 100644 index 000000000000..82616c5743dd --- /dev/null +++ b/.github/workflows/js.yml @@ -0,0 +1,42 @@ +name: JS Tests + +on: + push: + branches-ignore: + - "dependabot/**" + pull_request: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + NODE: 16 + +jobs: + run: + name: JS Tests + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE }} + cache: npm + + - name: Install npm dependencies + run: npm ci + + - name: Run dist + run: npm run js + + - name: Run JS tests + run: npm run js-test + + - name: Run Coveralls + uses: coverallsapp/github-action@1.1.3 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + path-to-lcov: "./js/coverage/lcov.info" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000000..816694ec2864 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,32 @@ +name: Lint + +on: + push: + branches-ignore: + - "dependabot/**" + pull_request: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + NODE: 16 + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ env.NODE }}" + cache: npm + + - name: Install npm dependencies + run: npm ci + + - name: Lint + run: npm run lint diff --git a/.gitignore b/.gitignore index 6b4387736144..2215d636addf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,8 @@ # Ignore docs files -_gh_pages -_site -site/docs/**/dist/ - -# Ignore ruby files -.ruby-version -.bundle -vendor/cache -vendor/bundle +/_site/ +# Hugo files +/resources/ +/.hugo_build.lock # Numerous always-ignore extensions *.diff @@ -34,14 +29,14 @@ vendor/bundle *.sublime-workspace nbproject Thumbs.db +/.vscode/ +# Local Netlify folder +.netlify # Komodo .komodotools *.komodoproject -# Jekyll metadata -docs/.jekyll-metadata - # Folders to ignore -node_modules -js/coverage +/js/coverage/ +/node_modules/ diff --git a/.stylelintignore b/.stylelintignore index 7bc488e5f871..0759a69acead 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -1,4 +1,5 @@ **/*.min.css **/dist/ **/vendor/ -/_gh_pages/ +/_site/ +/js/coverage/ diff --git a/.stylelintrc b/.stylelintrc index fce97867fc27..b948fe8e298a 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,328 +1,22 @@ { "extends": [ - "stylelint-config-standard", - "stylelint-config-recommended-scss" - ], - "plugins": [ - "stylelint-order" + "stylelint-config-twbs-bootstrap" ], "rules": { - "at-rule-empty-line-before": null, - "at-rule-name-space-after": "always", - "at-rule-no-unknown": null, - "at-rule-no-vendor-prefix": true, - "at-rule-semicolon-space-before": "never", - "block-closing-brace-empty-line-before": null, - "block-closing-brace-newline-after": null, - "block-opening-brace-space-before": null, - "color-named": "never", - "declaration-block-semicolon-newline-after": "always-multi-line", - "declaration-block-semicolon-newline-before": "never-multi-line", - "declaration-block-semicolon-space-after": "always-single-line", - "declaration-empty-line-before": null, - "declaration-no-important": true, - "font-family-name-quotes": "always-where-recommended", - "font-weight-notation": [ - "numeric", - { - "ignore": [ - "relative" - ] - } - ], - "function-url-no-scheme-relative": true, - "function-url-quotes": "always", - "length-zero-no-unit": true, - "max-empty-lines": 2, - "max-line-length": null, - "media-feature-name-no-unknown": [ - true, - { - "ignoreMediaFeatureNames": [ - "prefers-reduced-motion" - ] - } + "declaration-property-value-disallowed-list": { + "border": "none", + "outline": "none" + }, + "function-disallowed-list": [ + "calc" ], - "media-feature-name-no-vendor-prefix": true, - "media-feature-parentheses-space-inside": "never", - "media-feature-range-operator-space-after": "always", - "media-feature-range-operator-space-before": "never", - "no-descending-specificity": null, - "no-duplicate-selectors": true, - "number-leading-zero": "never", - "order/properties-order": [ - "position", - "top", - "right", - "bottom", - "left", - "z-index", - "box-sizing", - "display", - "flex", - "flex-align", - "flex-basis", - "flex-direction", - "flex-wrap", - "flex-flow", - "flex-shrink", - "flex-grow", - "flex-order", - "flex-pack", - "align-content", - "align-items", - "align-self", - "justify-content", - "order", - "float", - "width", - "min-width", - "max-width", - "height", - "min-height", - "max-height", - "padding", - "padding-top", - "padding-right", - "padding-bottom", - "padding-left", - "margin", - "margin-top", - "margin-right", - "margin-bottom", - "margin-left", - "overflow", - "overflow-x", - "overflow-y", - "-webkit-overflow-scrolling", - "-ms-overflow-x", - "-ms-overflow-y", - "-ms-overflow-style", - "columns", - "column-count", - "column-fill", - "column-gap", - "column-rule", - "column-rule-width", - "column-rule-style", - "column-rule-color", - "column-span", - "column-width", - "orphans", - "widows", - "clip", - "clear", - "font", - "font-family", - "font-size", - "font-style", - "font-weight", - "font-variant", - "font-size-adjust", - "font-stretch", - "font-effect", - "font-emphasize", - "font-emphasize-position", - "font-emphasize-style", - "font-smooth", - "src", - "hyphens", - "line-height", - "color", - "text-align", - "text-align-last", - "text-emphasis", - "text-emphasis-color", - "text-emphasis-style", - "text-emphasis-position", - "text-decoration", - "text-indent", - "text-justify", - "text-outline", - "-ms-text-overflow", - "text-overflow", - "text-overflow-ellipsis", - "text-overflow-mode", - "text-shadow", - "text-transform", - "text-wrap", - "-webkit-text-size-adjust", - "-ms-text-size-adjust", - "letter-spacing", - "-ms-word-break", - "word-break", - "word-spacing", - "-ms-word-wrap", - "word-wrap", - "overflow-wrap", - "tab-size", - "white-space", - "vertical-align", - "direction", - "unicode-bidi", - "list-style", - "list-style-position", - "list-style-type", - "list-style-image", - "pointer-events", - "-ms-touch-action", - "touch-action", - "cursor", - "visibility", - "zoom", - "table-layout", - "empty-cells", - "caption-side", - "border-spacing", - "border-collapse", - "content", - "quotes", - "counter-reset", - "counter-increment", - "resize", - "user-select", - "nav-index", - "nav-up", - "nav-right", - "nav-down", - "nav-left", - "background", - "background-color", - "background-image", - "filter", - "background-repeat", - "background-attachment", - "background-position", - "background-position-x", - "background-position-y", - "background-clip", - "background-origin", - "background-size", - "border", - "border-color", - "border-style", - "border-width", - "border-top", - "border-top-color", - "border-top-style", - "border-top-width", - "border-right", - "border-right-color", - "border-right-style", - "border-right-width", - "border-bottom", - "border-bottom-color", - "border-bottom-style", - "border-bottom-width", - "border-left", - "border-left-color", - "border-left-style", - "border-left-width", - "border-radius", - "border-top-left-radius", - "border-top-right-radius", - "border-bottom-right-radius", - "border-bottom-left-radius", - "border-image", - "border-image-source", - "border-image-slice", - "border-image-width", - "border-image-outset", - "border-image-repeat", - "outline", - "outline-width", - "outline-style", - "outline-color", - "outline-offset", - "box-shadow", - "opacity", - "-ms-interpolation-mode", - "page-break-after", - "page-break-before", - "page-break-inside", - "transition", - "transition-delay", - "transition-timing-function", - "transition-duration", - "transition-property", - "transform", - "transform-origin", - "perspective", - "appearance", - "animation", - "animation-name", - "animation-duration", - "animation-play-state", - "animation-timing-function", - "animation-delay", - "animation-iteration-count", - "animation-direction", - "animation-fill-mode", - "fill", - "stroke" - ], - "property-blacklist": [ + "property-disallowed-list": [ "border-radius", "border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius", "transition" - ], - "property-no-vendor-prefix": true, - "rule-empty-line-before": null, - "scss/at-function-named-arguments": "never", - "scss/at-function-parentheses-space-before": "never", - "scss/at-import-no-partial-leading-underscore": true, - "scss/at-mixin-argumentless-call-parentheses": null, - "scss/at-mixin-named-arguments": null, - "scss/at-mixin-parentheses-space-before": "never", - "scss/at-rule-no-unknown": true, - "scss/dollar-variable-colon-space-after": "at-least-one-space", - "scss/dollar-variable-colon-space-before": "never", - "scss/dollar-variable-default": [ - true, - { - "ignore": "local" - } - ], - "scss/dollar-variable-no-missing-interpolation": true, - "scss/media-feature-value-dollar-variable": null, - "scss/no-duplicate-dollar-variables": [ - null, - { - "ignoreInsideAtRules": [ - "if", - "mixin" - ] - } - ], - "scss/operator-no-newline-after": true, - "scss/operator-no-newline-before": true, - "scss/operator-no-unspaced": true, - "selector-attribute-quotes": "always", - "selector-class-pattern": "^[a-z][a-z0-9\\-]*[a-z0-9]$", - "selector-list-comma-newline-after": "always", - "selector-list-comma-newline-before": "never-multi-line", - "selector-list-comma-space-after": "always-single-line", - "selector-list-comma-space-before": "never-single-line", - "selector-max-attribute": 2, - "selector-max-class": 4, - "selector-max-combinators": 4, - "selector-max-compound-selectors": 4, - "selector-max-empty-lines": 1, - "selector-max-id": 0, - "selector-max-specificity": null, - "selector-max-type": 2, - "selector-max-universal": 1, - "selector-no-qualifying-type": true, - "selector-no-vendor-prefix": true, - "shorthand-property-no-redundant-values": true, - "string-quotes": "double", - "value-keyword-case": "lower", - "value-list-comma-newline-after": "never-multi-line", - "value-list-comma-newline-before": "never-multi-line", - "value-list-comma-space-after": "always", - "value-no-vendor-prefix": true + ] } } diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b8d19ad258ec..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -addons: - chrome: stable -language: node_js -git: - depth: 3 -node_js: - - "6" - - "8" -install: - - bundle install --deployment --jobs=3 --retry=3 --clean - - npm install -before_script: - - google-chrome-stable --product-version -script: - - npm test || travis_terminate 1 - - if [[ "$TRAVIS_NODE_VERSION" = "8" ]]; then npm run check-broken-links; fi - - if [[ "$TRAVIS_NODE_VERSION" = "8" && "$TRAVIS_EVENT_TYPE" = "push" && ! `git log --format=%B --no-merges -n 1 | grep '\[skip browser\]'` ]]; then npm run js-test-cloud; fi -after_success: - - if [[ "$TRAVIS_NODE_VERSION" = "8" ]]; then npm run coveralls; fi -cache: - directories: - - node_modules - - vendor/bundle -notifications: - email: false diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 9d9922f25f4d..0d2e5269557a 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -40,7 +40,4 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html][version] - -[homepage]: https://www.contributor-covenant.org/ -[version]: https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available at diff --git a/Gemfile b/Gemfile deleted file mode 100644 index d4fdb3b90778..000000000000 --- a/Gemfile +++ /dev/null @@ -1,9 +0,0 @@ -source 'https://rubygems.org' - -group :development, :test do - gem 'jekyll', '~> 3.8.5' - gem 'jekyll-redirect-from', '~> 0.14.0' - gem 'jekyll-sitemap', '~> 1.2.0' - gem 'jekyll-toc', '~> 0.9.1' - gem 'wdm', '~> 0.1.1', :install_if => Gem.win_platform? -end diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index eb0f1427e39e..000000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,82 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) - colorator (1.1.0) - concurrent-ruby (1.1.4) - em-websocket (0.5.1) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) - eventmachine (1.2.7) - eventmachine (1.2.7-x64-mingw32) - ffi (1.9.25) - ffi (1.9.25-x64-mingw32) - forwardable-extended (2.6.0) - http_parser.rb (0.6.0) - i18n (0.9.5) - concurrent-ruby (~> 1.0) - jekyll (3.8.5) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 0.7) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (~> 1.14) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - jekyll-redirect-from (0.14.0) - jekyll (~> 3.3) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-sitemap (1.2.0) - jekyll (~> 3.3) - jekyll-toc (0.9.1) - nokogiri (~> 1.8) - jekyll-watch (2.1.2) - listen (~> 3.0) - kramdown (1.17.0) - liquid (4.0.1) - listen (3.1.5) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) - mercenary (0.3.6) - mini_portile2 (2.4.0) - nokogiri (1.9.0) - mini_portile2 (~> 2.4.0) - nokogiri (1.9.0-x64-mingw32) - mini_portile2 (~> 2.4.0) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (3.0.3) - rb-fsevent (0.10.3) - rb-inotify (0.10.0) - ffi (~> 1.0) - rouge (3.3.0) - ruby_dep (1.5.0) - safe_yaml (1.0.4) - sass (3.7.2) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - wdm (0.1.1) - -PLATFORMS - ruby - x64-mingw32 - -DEPENDENCIES - jekyll (~> 3.8.5) - jekyll-redirect-from (~> 0.14.0) - jekyll-sitemap (~> 1.2.0) - jekyll-toc (~> 0.9.1) - wdm (~> 0.1.1) - -BUNDLED WITH - 1.17.2 diff --git a/LICENSE b/LICENSE index 86f4b8ca04f8..dda75ca9a5bb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2011-2018 Twitter, Inc. -Copyright (c) 2011-2018 The Bootstrap Authors +Copyright (c) 2011-2022 Twitter, Inc. +Copyright (c) 2011-2022 The Bootstrap Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c6535efe86a4..d7b707f1ba89 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- Bootstrap logo + Bootstrap logo

@@ -9,12 +9,12 @@

Sleek, intuitive, and powerful front-end framework for faster and easier web development.
- Explore Bootstrap docs » + Explore Bootstrap docs »

- Report bug + Report bug · - Request feature + Request feature · Themes · @@ -41,38 +41,38 @@ Several quick start options are available: -- [Download the latest release.](https://github.com/twbs/bootstrap/archive/v4.2.1.zip) +- [Download the latest release.](https://github.com/twbs/bootstrap/archive/v4.6.2.zip) - Clone the repo: `git clone https://github.com/twbs/bootstrap.git` - Install with [npm](https://www.npmjs.com/): `npm install bootstrap` -- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@4.2.1` -- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:4.2.1` +- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@4.6.2` +- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:4.6.2` - Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass` -Read the [Getting started page](https://getbootstrap.com/docs/4.2/getting-started/introduction/) for information on the framework contents, templates and examples, and more. +Read the [Getting started page](https://getbootstrap.com/docs/4.6/getting-started/introduction/) for information on the framework contents, templates and examples, and more. ## Status [![Slack](https://bootstrap-slack.herokuapp.com/badge.svg)](https://bootstrap-slack.herokuapp.com/) -[![Build Status](https://img.shields.io/travis/twbs/bootstrap/v4-dev.svg)](https://travis-ci.org/twbs/bootstrap) -[![npm version](https://img.shields.io/npm/v/bootstrap.svg)](https://www.npmjs.com/package/bootstrap) -[![Gem version](https://img.shields.io/gem/v/bootstrap.svg)](https://rubygems.org/gems/bootstrap) -[![Meteor Atmosphere](https://img.shields.io/badge/meteor-twbs%3Abootstrap-blue.svg)](https://atmospherejs.com/twbs/bootstrap) -[![Packagist Prerelease](https://img.shields.io/packagist/vpre/twbs/bootstrap.svg)](https://packagist.org/packages/twbs/bootstrap) -[![NuGet](https://img.shields.io/nuget/vpre/bootstrap.svg)](https://www.nuget.org/packages/bootstrap/absoluteLatest) -[![peerDependencies Status](https://img.shields.io/david/peer/twbs/bootstrap.svg)](https://david-dm.org/twbs/bootstrap?type=peer) -[![devDependency Status](https://img.shields.io/david/dev/twbs/bootstrap.svg)](https://david-dm.org/twbs/bootstrap?type=dev) -[![Coverage Status](https://img.shields.io/coveralls/github/twbs/bootstrap/v4-dev.svg)](https://coveralls.io/github/twbs/bootstrap?branch=v4-dev) -[![CSS gzip size](https://img.badgesize.io/twbs/bootstrap/v4-dev/dist/css/bootstrap.min.css?compression=gzip&label=CSS+gzip+size)](https://github.com/twbs/bootstrap/tree/v4-dev/dist/css/bootstrap.min.css) -[![JS gzip size](https://img.badgesize.io/twbs/bootstrap/v4-dev/dist/js/bootstrap.min.js?compression=gzip&label=JS+gzip+size)](https://github.com/twbs/bootstrap/tree/v4-dev/dist/js/bootstrap.min.js) +[![Build Status](https://img.shields.io/github/workflow/status/twbs/bootstrap/JS%20Tests/v4-dev?label=JS%20Tests&logo=github)](https://github.com/twbs/bootstrap/actions?query=workflow%3AJS+Tests+branch%3Av4-dev) +[![npm version](https://img.shields.io/npm/v/bootstrap)](https://www.npmjs.com/package/bootstrap) +[![Gem version](https://img.shields.io/gem/v/bootstrap)](https://rubygems.org/gems/bootstrap) +[![Meteor Atmosphere](https://img.shields.io/badge/meteor-twbs%3Abootstrap-blue)](https://atmospherejs.com/twbs/bootstrap) +[![Packagist Prerelease](https://img.shields.io/packagist/vpre/twbs/bootstrap)](https://packagist.org/packages/twbs/bootstrap) +[![NuGet](https://img.shields.io/nuget/vpre/bootstrap)](https://www.nuget.org/packages/bootstrap/absoluteLatest) +[![Coverage Status](https://img.shields.io/coveralls/github/twbs/bootstrap/v4-dev)](https://coveralls.io/github/twbs/bootstrap?branch=v4-dev) +[![CSS gzip size](https://img.badgesize.io/twbs/bootstrap/v4-dev/dist/css/bootstrap.min.css?compression=gzip&label=CSS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/v4-dev/dist/css/bootstrap.min.css) +[![JS gzip size](https://img.badgesize.io/twbs/bootstrap/v4-dev/dist/js/bootstrap.min.js?compression=gzip&label=JS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/v4-dev/dist/js/bootstrap.min.js) [![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229)](https://www.browserstack.com/automate/public-build/SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229) -[![Backers on Open Collective](https://opencollective.com/bootstrap/backers/badge.svg)](#backers) -[![Sponsors on Open Collective](https://opencollective.com/bootstrap/sponsors/badge.svg)](#sponsors) +[![Backers on Open Collective](https://img.shields.io/opencollective/backers/bootstrap)](#backers) +[![Sponsors on Open Collective](https://img.shields.io/opencollective/sponsors/bootstrap)](#sponsors) ## What's included -Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this: +Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. + +

Download contents ```text bootstrap/ @@ -100,48 +100,45 @@ bootstrap/ ├── bootstrap.min.js └── bootstrap.min.js.map ``` +
-We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [source maps](https://developers.google.com/web/tools/chrome-devtools/debug/readability/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/), but not [jQuery](https://jquery.com/). +We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [Source maps](https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/), but not [jQuery](https://jquery.com/). ## Bugs and feature requests -Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new). +Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/v4-dev/.github/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new). ## Documentation -Bootstrap's documentation, included in this repo in the root directory, is built with [Jekyll](https://jekyllrb.com/) and publicly hosted on GitHub Pages at . The docs may also be run locally. +Bootstrap's documentation, included in this repo in the root directory, is built with [Hugo](https://gohugo.io/) and publicly hosted on GitHub Pages at . The docs may also be run locally. -Documentation search is powered by [Algolia's DocSearch](https://community.algolia.com/docsearch/). Working on our search? Be sure to set `debug: true` in `site/docs/4.2/assets/js/src/search.js` file. +Documentation search is powered by [Algolia's DocSearch](https://community.algolia.com/docsearch/). Working on our search? Be sure to set `debug: true` in `site/assets/js/search.js`. ### Running documentation locally -1. Run through the [tooling setup](https://getbootstrap.com/docs/4.2/getting-started/build-tools/#tooling-setup) to install Jekyll (the site builder) and other Ruby dependencies with `bundle install`. -2. Run `npm install` to install Node.js dependencies. +1. Run `npm install` to install the Node.js dependencies, including Hugo (the site builder). +2. Run `npm run test` (or a specific npm script) to rebuild distributed CSS and JavaScript files, as well as our docs assets. 3. Run `npm start` to compile CSS and JavaScript files, generate our docs, and watch for changes. -4. Open `http://localhost:9001` in your browser, and voilà. +4. Open `http://localhost:9001/` in your browser, and voilà. -Learn more about using Jekyll by reading its [documentation](https://jekyllrb.com/docs/). +Learn more about using Hugo by reading its [documentation](https://gohugo.io/documentation/). ### Documentation for previous releases -- For v2.3.2: -- For v3.3.x: -- For v3.4.0: -- For v4.0.x: -- For v4.1.x: +You can find all our previous releases docs on . [Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download. ## Contributing -Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development. +Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/v4-dev/.github/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development. -Moreover, if your pull request contains JavaScript patches or features, you must include [relevant unit tests](https://github.com/twbs/bootstrap/tree/master/js/tests). All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo). +Moreover, if your pull request contains JavaScript patches or features, you must include [relevant unit tests](https://github.com/twbs/bootstrap/tree/v4-dev/js/tests). All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo). -Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/master/.editorconfig) for easy use in common text editors. Read more and download plugins at . +Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/v4-dev/.editorconfig) for easy use in common text editors. Read more and download plugins at . ## Community @@ -151,7 +148,7 @@ Get updates on Bootstrap's development and chat with the project maintainers and - Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap). - Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com/). - Join [the official Slack room](https://bootstrap-slack.herokuapp.com/). -- Chat with fellow Bootstrappers in IRC. On the `irc.freenode.net` server, in the `##bootstrap` channel. +- Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel. - Implementation help may be found at Stack Overflow (tagged [`bootstrap-4`](https://stackoverflow.com/questions/tagged/bootstrap-4)). - Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability. @@ -179,19 +176,12 @@ See [the Releases section of our GitHub project](https://github.com/twbs/bootstr ## Thanks - BrowserStack Logo + BrowserStack Logo Thanks to [BrowserStack](https://www.browserstack.com/) for providing the infrastructure that allows us to test in real browsers! -## Backers - -Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/bootstrap#backer)] - -[![Bakers](https://opencollective.com/bootstrap/backers.svg?width=890)](https://opencollective.com/bootstrap#backers) - - ## Sponsors Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/bootstrap#sponsor)] @@ -208,6 +198,13 @@ Support this project by becoming a sponsor. Your logo will show up here with a l [![](https://opencollective.com/bootstrap/sponsor/9/avatar.svg)](https://opencollective.com/bootstrap/sponsor/9/website) +## Backers + +Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/bootstrap#backer)] + +[![Backers](https://opencollective.com/bootstrap/backers.svg?width=890)](https://opencollective.com/bootstrap#backers) + + ## Copyright and license -Code and documentation copyright 2011-2018 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors) and [Twitter, Inc.](https://twitter.com) Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/master/LICENSE). Docs released under [Creative Commons](https://github.com/twbs/bootstrap/blob/master/docs/LICENSE). +Code and documentation copyright 2011-2022 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors) and [Twitter, Inc.](https://twitter.com) Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..e79dcd8d2038 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,7 @@ +# Reporting Security Issues + +The Bootstrap team and community take security issues in Bootstrap seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. + +To report a security issue, email [security@getbootstrap.com](mailto:security@getbootstrap.com) and include the word "SECURITY" in the subject line. + +We'll endeavor to respond quickly, and will keep you updated throughout the process. diff --git a/_config.yml b/_config.yml deleted file mode 100644 index 10c4b4a58e40..000000000000 --- a/_config.yml +++ /dev/null @@ -1,68 +0,0 @@ -# Dependencies -markdown: kramdown -highlighter: rouge - -kramdown: - auto_ids: true - -# Permalinks -permalink: pretty - -# Server -source: "site" -destination: ./_gh_pages -host: "localhost" -port: 9001 -baseurl: "" -url: "https://getbootstrap.com" -encoding: UTF-8 -exclude: - - docs/4.2/assets/scss/ - -plugins: - - jekyll-redirect-from - - jekyll-sitemap - - jekyll-toc - -# Social -title: Bootstrap -description: "The most popular HTML, CSS, and JS library in the world." -twitter: getbootstrap -authors: "Mark Otto, Jacob Thornton, and Bootstrap contributors" -social_image_path: /docs/4.2/assets/brand/bootstrap-social.png -social_logo_path: /docs/4.2/assets/brand/bootstrap-social-logo.png - -# Custom variables -current_version: 4.2.1 -current_ruby_version: 4.2.1 -docs_version: 4.2 -repo: "https://github.com/twbs/bootstrap" -slack: "https://bootstrap-slack.herokuapp.com" -opencollective: "https://opencollective.com/bootstrap" -blog: "https://blog.getbootstrap.com" -expo: "https://expo.getbootstrap.com" -themes: "https://themes.getbootstrap.com" - -download: - source: "https://github.com/twbs/bootstrap/archive/v4.2.1.zip" - dist: "https://github.com/twbs/bootstrap/releases/download/v4.2.1/bootstrap-4.2.1-dist.zip" - -cdn: - # See https://www.srihash.org for info on how to generate the hashes - css: "https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" - css_hash: "sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" - js: "https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" - js_hash: "sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" - js_bundle: "https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.bundle.min.js" - js_bundle_hash: "sha384-zDnhMsjVZfS3hiP7oCBRmfjkQC4fzxVxFhBx8Hkz2aZX8gEvA/jsP3eXRCvzTofP" - jquery: "https://code.jquery.com/jquery-3.3.1.slim.min.js" - jquery_hash: "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" - popper: "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" - popper_hash: "sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" - -toc: - min_level: 2 - max_level: 4 - no_toc_section_class: - - "bd-callout" - - "bd-example" diff --git a/build/.eslintrc.json b/build/.eslintrc.json index 76e7f37b6348..679bd26f7ba2 100644 --- a/build/.eslintrc.json +++ b/build/.eslintrc.json @@ -8,13 +8,7 @@ }, "extends": "../.eslintrc.json", "rules": { - "consistent-return": "off", - "func-style": "off", "no-console": "off", - "no-magic-numbers": "off", - "no-process-env": "off", - "no-process-exit": "off", - "no-sync": "off", - "spaced-comment": "off" + "strict": "error" } } diff --git a/build/banner.js b/build/banner.js index 453fc3b6e0b2..df82ff32edf3 100644 --- a/build/banner.js +++ b/build/banner.js @@ -7,7 +7,7 @@ function getBanner(pluginFilename) { return `/*! * Bootstrap${pluginFilename ? ` ${pluginFilename}` : ''} v${pkg.version} (${pkg.homepage}) * Copyright 2011-${year} ${pkg.author} - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */` } diff --git a/build/build-plugins.js b/build/build-plugins.js index 3240ee5d0538..9e33ddb655c6 100644 --- a/build/build-plugins.js +++ b/build/build-plugins.js @@ -1,28 +1,26 @@ +#!/usr/bin/env node + /*! * Script to build our plugins to use them separately. - * Copyright 2018 The Bootstrap Authors - * Copyright 2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * 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('path') -const rollup = require('rollup') -const babel = require('rollup-plugin-babel') -const banner = require('./banner.js') +const path = require('path') +const rollup = require('rollup') +const { babel } = require('@rollup/plugin-babel') +const banner = require('./banner.js') -const TEST = process.env.NODE_ENV === 'test' +const TEST = process.env.NODE_ENV === 'test' const plugins = [ babel({ - exclude: 'node_modules/**', // Only transpile our source code - externalHelpersWhitelist: [ // Include only required helpers - 'defineProperties', - 'createClass', - 'inheritsLoose', - 'defineProperty', - 'objectSpread' - ] + // Only transpile our source code + exclude: 'node_modules/**', + // Include the helpers in each file, at most one copy of each + babelHelpers: 'bundled' }) ] const bsPlugins = { @@ -41,7 +39,7 @@ const bsPlugins = { } const rootPath = TEST ? '../js/coverage/dist/' : '../js/dist/' -function build(plugin) { +const build = async plugin => { console.log(`Building ${plugin} plugin...`) const external = ['jquery', 'popper.js'] @@ -63,23 +61,32 @@ function build(plugin) { } const pluginFilename = `${plugin.toLowerCase()}.js` - - rollup.rollup({ + const bundle = await rollup.rollup({ input: bsPlugins[plugin], plugins, external - }).then((bundle) => { - bundle.write({ - banner: banner(pluginFilename), - format: 'umd', - name: plugin, - sourcemap: true, - globals, - file: path.resolve(__dirname, `${rootPath}${pluginFilename}`) - }) - .then(() => console.log(`Building ${plugin} plugin... Done!`)) - .catch((err) => console.error(`${plugin}: ${err}`)) }) + + await bundle.write({ + banner: banner(pluginFilename), + 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) + } } -Object.keys(bsPlugins).forEach((plugin) => build(plugin)) +main() diff --git a/build/change-version.js b/build/change-version.js old mode 100755 new mode 100644 index 7102dc0830d2..e035eba952ea --- a/build/change-version.js +++ b/build/change-version.js @@ -2,103 +2,80 @@ /*! * Script to update version number references in the project. - * Copyright 2017-2018 The Bootstrap Authors - * Copyright 2017-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * Copyright 2017-2022 The Bootstrap Authors + * Copyright 2017-2022 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ 'use strict' -const fs = require('fs') +const fs = require('fs').promises const path = require('path') -const sh = require('shelljs') +const globby = require('globby') -sh.config.fatal = true +const VERBOSE = process.argv.includes('--verbose') +const DRY_RUN = process.argv.includes('--dry') || process.argv.includes('--dry-run') + +// These are the filetypes we only care about replacing the version +const GLOB = [ + '**/*.{css,html,js,json,md,scss,txt,yml}' +] +const GLOBBY_OPTIONS = { + cwd: path.join(__dirname, '..'), + gitignore: true +} // Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37 function regExpQuote(string) { - return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&') + return string.replace(/[$()*+.?[\\\]^{|}-]/g, '\\$&') } function regExpQuoteReplacement(string) { - return string.replace(/[$]/g, '$$') + return string.replace(/\$/g, '$$') } -const DRY_RUN = false +async function replaceRecursively(file, oldVersion, newVersion) { + const originalString = await fs.readFile(file, 'utf8') + const newString = originalString.replace( + new RegExp(regExpQuote(oldVersion), 'g'), regExpQuoteReplacement(newVersion) + ) -function walkAsync(directory, excludedDirectories, fileCallback, errback) { - if (excludedDirectories.has(path.parse(directory).base)) { + // No need to move any further if the strings are identical + if (originalString === newString) { return } - fs.readdir(directory, (err, names) => { - if (err) { - errback(err) - return - } - names.forEach((name) => { - const filepath = path.join(directory, name) - fs.lstat(filepath, (err, stats) => { - if (err) { - process.nextTick(errback, err) - return - } - if (stats.isDirectory()) { - process.nextTick(walkAsync, filepath, excludedDirectories, fileCallback, errback) - } else if (stats.isFile()) { - process.nextTick(fileCallback, filepath) - } - }) - }) - }) -} -function replaceRecursively(directory, excludedDirectories, allowedExtensions, original, replacement) { - original = new RegExp(regExpQuote(original), 'g') - replacement = regExpQuoteReplacement(replacement) - const updateFile = DRY_RUN ? (filepath) => { - if (allowedExtensions.has(path.parse(filepath).ext)) { - console.log(`FILE: ${filepath}`) - } else { - console.log(`EXCLUDED:${filepath}`) - } - } : (filepath) => { - if (allowedExtensions.has(path.parse(filepath).ext)) { - sh.sed('-i', original, replacement, filepath) - } + if (VERBOSE) { + console.log(`FILE: ${file}`) } - walkAsync(directory, excludedDirectories, updateFile, (err) => { - console.error('ERROR while traversing directory!:') - console.error(err) - process.exit(1) - }) + + if (DRY_RUN) { + return + } + + await fs.writeFile(file, newString, 'utf8') } -function main(args) { - if (args.length !== 2) { - console.error('USAGE: change-version old_version new_version') +async function main(args) { + let [oldVersion, newVersion] = args + + if (!oldVersion || !newVersion) { + console.error('USAGE: change-version old_version new_version [--verbose] [--dry[-run]]') console.error('Got arguments:', args) process.exit(1) } - const oldVersion = args[0] - const newVersion = args[1] - const EXCLUDED_DIRS = new Set([ - '.git', - 'node_modules', - 'vendor' - ]) - const INCLUDED_EXTENSIONS = new Set([ - // This extension whitelist is how we avoid modifying binary files - '', - '.css', - '.html', - '.js', - '.json', - '.md', - '.scss', - '.txt', - '.yml' - ]) - replaceRecursively('.', EXCLUDED_DIRS, INCLUDED_EXTENSIONS, oldVersion, newVersion) + + // Strip any leading `v` from arguments because otherwise we will end up with duplicate `v`s + [oldVersion, newVersion] = [oldVersion, newVersion].map(arg => arg.startsWith('v') ? arg.slice(1) : arg) + + try { + const files = await globby(GLOB, GLOBBY_OPTIONS) + + await Promise.all(files.map(file => replaceRecursively(file, oldVersion, newVersion))) + } catch (error) { + console.error(error) + process.exit(1) + } } main(process.argv.slice(2)) diff --git a/build/generate-sri.js b/build/generate-sri.js index 309f29bd287b..9685899261f8 100644 --- a/build/generate-sri.js +++ b/build/generate-sri.js @@ -5,9 +5,9 @@ * Remember to use the same vendor files as the CDN ones, * otherwise the hashes won't match! * - * Copyright 2017-2018 The Bootstrap Authors - * Copyright 2017-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * Copyright 2017-2022 The Bootstrap Authors + * Copyright 2017-2022 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ 'use strict' @@ -21,11 +21,11 @@ const pkg = require('../package.json') sh.config.fatal = true -const configFile = path.join(__dirname, '../_config.yml') +const configFile = path.join(__dirname, '../config.yml') // Array of objects which holds the files to generate SRI hashes for. // `file` is the path from the root folder -// `configPropertyName` is the _config.yml variable's name of the file +// `configPropertyName` is the config.yml variable's name of the file const files = [ { file: 'dist/css/bootstrap.min.css', @@ -35,21 +35,21 @@ const files = [ file: 'dist/js/bootstrap.min.js', configPropertyName: 'js_hash' }, - { - file: `site/docs/${pkg.version_short}/assets/js/vendor/jquery-slim.min.js`, - configPropertyName: 'jquery_hash' - }, { file: 'dist/js/bootstrap.bundle.min.js', configPropertyName: 'js_bundle_hash' }, + { + file: `site/static/docs/${pkg.config.version_short}/assets/js/vendor/jquery.slim.min.js`, + configPropertyName: 'jquery_hash' + }, { file: 'node_modules/popper.js/dist/umd/popper.min.js', configPropertyName: 'popper_hash' } ] -files.forEach((file) => { +files.forEach(file => { fs.readFile(file.file, 'utf8', (err, data) => { if (err) { throw err @@ -61,6 +61,6 @@ files.forEach((file) => { console.log(`${file.configPropertyName}: ${integrity}`) - sh.sed('-i', new RegExp(`(\\s${file.configPropertyName}:\\s+"|')(\\S+)("|')`), `$1${integrity}$3`, configFile) + sh.sed('-i', new RegExp(`^(\\s+${file.configPropertyName}:\\s+["'])\\S*(["'])`), `$1${integrity}$2`, configFile) }) }) diff --git a/build/postcss.config.js b/build/postcss.config.js index 157291ffd2e2..ef416258f7fc 100644 --- a/build/postcss.config.js +++ b/build/postcss.config.js @@ -1,14 +1,18 @@ 'use strict' -module.exports = (ctx) => ({ - map: ctx.file.dirname.includes('examples') ? false : { - inline: false, - annotation: true, - sourcesContent: true - }, - plugins: { - autoprefixer: { - cascade: false +module.exports = ctx => { + return { + map: ctx.file.dirname.includes('examples') ? + false : + { + inline: false, + annotation: true, + sourcesContent: true + }, + plugins: { + autoprefixer: { + cascade: false + } } } -}) +} diff --git a/build/rollup.config.js b/build/rollup.config.js index e81a07ef58b2..e2d2b125efe6 100644 --- a/build/rollup.config.js +++ b/build/rollup.config.js @@ -1,24 +1,20 @@ 'use strict' -const path = require('path') -const babel = require('rollup-plugin-babel') -const resolve = require('rollup-plugin-node-resolve') -const banner = require('./banner.js') +const path = require('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' +const BUNDLE = process.env.BUNDLE === 'true' -let fileDest = 'bootstrap.js' +let fileDest = 'bootstrap.js' const external = ['jquery', 'popper.js'] const plugins = [ babel({ - exclude: 'node_modules/**', // Only transpile our source code - externalHelpersWhitelist: [ // Include only required helpers - 'defineProperties', - 'createClass', - 'inheritsLoose', - 'defineProperty', - 'objectSpread' - ] + // Only transpile our source code + exclude: 'node_modules/**', + // Include the helpers in the bundle, at most one copy of each + babelHelpers: 'bundled' }) ] const globals = { @@ -31,11 +27,11 @@ if (BUNDLE) { // Remove last entry in external array to bundle Popper external.pop() delete globals['popper.js'] - plugins.push(resolve()) + plugins.push(nodeResolve()) } module.exports = { - input: path.resolve(__dirname, '../js/src/index.js'), + input: path.resolve(__dirname, '../js/index.js'), output: { banner, file: path.resolve(__dirname, `../dist/js/${fileDest}`), diff --git a/build/ship.sh b/build/ship.sh deleted file mode 100755 index 2892843839cd..000000000000 --- a/build/ship.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash -# -# Usage -# --------------- -# 1. Clone second version of Bootstrap in sibling directory named `bs-docs`. -# 2. Within `bs-docs` copy, switch to `gh-pages` branch. -# 3. Pull latest, re-bundle, re-npm. -# 4. Run script. - -red=$'\e[1;31m' -green=$'\e[1;32m' -#blue=$'\e[1;34m' -magenta=$'\e[1;35m' -#cyan=$'\e[1;36m' -end=$'\e[0m' - -# Get current version from package.json -current_version=$(node -p "require('./package.json').version") - -if [[ $# -lt 1 ]]; then - printf "\n%s⚠️ Shipping aborted. You must specify a version.\n%s" $red $end - exit 1 -fi - -# Pulling latest changes, just to be sure -printf "\n%s=======================================================%s" $magenta $end -printf "\n%sPulling latest changes...%s" $magenta $end -printf "\n%s=======================================================\n\n%s" $magenta $end -git pull origin v4-dev - -# Update version number -printf "\n%s=======================================================%s" $magenta $end -printf "\n%sUpdating version number...%s" $magenta $end -printf "\n%s=======================================================\n%s" $magenta $end -npm run release-version "$current_version" "$1" - -# Build release -printf "\n%s=======================================================%s" $magenta $end -printf "\n%sBuilding release...%s" $magenta $end -printf "\n%s=======================================================\n%s" $magenta $end -npm run release - -# Copy the contents of the built docs site over to `bs-docs` repo -printf "\n%s=======================================================%s" $magenta $end -printf "\n%sCopy it over...%s" $magenta $end -printf "\n%s=======================================================\n%s" $magenta $end -cp -rf _gh_pages/. ../bs-docs/ -printf "\nDone!\n" - -printf "\n%s=======================================================%s" $green $end -printf "\n%sSuccess, $1 is ready to review and publish.%s" $green $end -printf "\n%s=======================================================\n\n%s" $green $end diff --git a/build/svgo.yml b/build/svgo.yml deleted file mode 100644 index 047e6947f0ce..000000000000 --- a/build/svgo.yml +++ /dev/null @@ -1,57 +0,0 @@ -# Usage: -# install svgo globally: `npm i -g svgo` -# svgo --config=build/svgo.yml --input=foo.svg - -# https://github.com/svg/svgo/blob/master/docs/how-it-works/en.md -# replace default config - -multipass: true -#full: true - -# https://github.com/svg/svgo/blob/master/lib/svgo/js2svg.js#L6 for more config options - -js2svg: - pretty: true - indent: 2 - -plugins: - # remove this with IE 11 is no longer supported - - addAttributesToSVGElement: - attributes: - - focusable: false - - cleanupAttrs: true - - cleanupEnableBackground: true - - cleanupIDs: true - - cleanupListOfValues: true - - cleanupNumericValues: true - - collapseGroups: true - - convertColors: true - - convertPathData: true - - convertShapeToPath: true - - convertStyleToAttrs: true - - convertTransform: true - - inlineStyles: true - - mergePaths: true - - minifyStyles: true - - moveElemsAttrsToGroup: true - - moveGroupAttrsToElems: true - - removeComments: true - - removeDesc: true - - removeDoctype: true - - removeEditorsNSData: true - - removeEmptyAttrs: true - - removeEmptyContainers: true - - removeEmptyText: true - - removeHiddenElems: true - - removeMetadata: true - - removeNonInheritableGroupAttrs: true - - removeTitle: false - - removeUnknownsAndDefaults: - keepRoleAttr: true - - removeUnusedNS: true - - removeUselessDefs: true - - removeUselessStrokeAndFill: true - - removeViewBox: false - - removeXMLNS: false - - removeXMLProcInst: true - - sortAttrs: true diff --git a/build/vnu-jar.js b/build/vnu-jar.js index b990ba7b78ed..54a71d024f41 100644 --- a/build/vnu-jar.js +++ b/build/vnu-jar.js @@ -2,53 +2,48 @@ /*! * Script to run vnu-jar if Java is available. - * Copyright 2017-2018 The Bootstrap Authors - * Copyright 2017-2018 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * Copyright 2017-2022 The Bootstrap Authors + * Copyright 2017-2022 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ 'use strict' -const childProcess = require('child_process') +const { execFile, spawn } = require('child_process') const vnu = require('vnu-jar') -childProcess.exec('java -version', (error, stdout, stderr) => { +execFile('java', ['-version'], (error, stdout, stderr) => { if (error) { console.error('Skipping vnu-jar test; Java is missing.') return } - const is32bitJava = !stderr.match(/64-Bit/) + const is32bitJava = !/64-Bit/.test(stderr) // vnu-jar accepts multiple ignores joined with a `|`. - // Also note that the ignores are regular expressions. + // Also note that the ignores are string regular expressions. const ignores = [ // "autocomplete" is included in ') - assert.ok(!$btn.hasClass('active'), 'btn does not have active class') + assert.false($btn.hasClass('active'), 'btn does not have active class') $btn.bootstrapButton('toggle') - assert.ok($btn.hasClass('active'), 'btn has class active') + assert.true($btn.hasClass('active'), 'btn has class active') }) QUnit.test('should toggle active when btn children are clicked', function (assert) { @@ -48,9 +50,9 @@ $(function () { $btn .append($inner) .appendTo('#qunit-fixture') - assert.ok(!$btn.hasClass('active'), 'btn does not have active class') + assert.false($btn.hasClass('active'), 'btn does not have active class') $inner.trigger('click') - assert.ok($btn.hasClass('active'), 'btn has class active') + assert.true($btn.hasClass('active'), 'btn has class active') }) QUnit.test('should toggle aria-pressed', function (assert) { @@ -61,6 +63,22 @@ $(function () { assert.strictEqual($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') }) + QUnit.test('should not toggle aria-pressed on buttons with disabled class', function (assert) { + assert.expect(2) + var $btn = $('') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $btn.bootstrapButton('toggle') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is still false') + }) + + QUnit.test('should not toggle aria-pressed on buttons that are disabled', function (assert) { + assert.expect(2) + var $btn = $('') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $btn.bootstrapButton('toggle') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is still false') + }) + QUnit.test('should toggle aria-pressed on buttons with container', function (assert) { assert.expect(1) var groupHTML = '
' + @@ -84,13 +102,73 @@ $(function () { assert.strictEqual($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') }) + QUnit.test('should assign active class on page load to buttons with aria-pressed="true"', function (assert) { + assert.expect(1) + var done = assert.async() + var $btn = $('') + $btn.appendTo('#qunit-fixture') + $(window).trigger($.Event('load')) + setTimeout(function () { + assert.true($btn.hasClass('active'), 'button with aria-pressed="true" has been given class active') + done() + }, 5) + }) + + QUnit.test('should assign active class on page load to button checkbox with checked attribute', function (assert) { + assert.expect(1) + var done = assert.async() + var groupHTML = '
' + + '' + + '
' + var $group = $(groupHTML).appendTo('#qunit-fixture') + var $btn = $group.children().eq(0) + + $(window).trigger($.Event('load')) + setTimeout(function () { + assert.true($btn.hasClass('active'), 'checked checkbox button has been given class active') + done() + }, 5) + }) + + QUnit.test('should remove active class on page load from buttons without aria-pressed="true"', function (assert) { + assert.expect(1) + var done = assert.async() + var $btn = $('') + $btn.appendTo('#qunit-fixture') + $(window).trigger($.Event('load')) + setTimeout(function () { + assert.false($btn.hasClass('active'), 'button without aria-pressed="true" has had active class removed') + done() + }, 5) + }) + + QUnit.test('should remove active class on page load from button checkbox without checked attribute', function (assert) { + assert.expect(1) + var done = assert.async() + var groupHTML = '
' + + '' + + '
' + var $group = $(groupHTML).appendTo('#qunit-fixture') + var $btn = $group.children().eq(0) + + $(window).trigger($.Event('load')) + setTimeout(function () { + assert.false($btn.hasClass('active'), 'unchecked checkbox button has had active class removed') + done() + }, 5) + }) + QUnit.test('should trigger input change event when toggled button has input field', function (assert) { assert.expect(1) var done = assert.async() var groupHTML = '
' + '' + '
' var $group = $(groupHTML).appendTo('#qunit-fixture') @@ -104,8 +182,34 @@ $(function () { $group.find('label').trigger('click') }) + QUnit.test('should trigger label change event only once', function (assert) { + assert.expect(1) + var done = assert.async() + var countChangeEvent = 0 + + var groupHTML = '
' + + '' + + '
' + var $group = $(groupHTML).appendTo('#qunit-fixture') + + var $btn = $group.children().eq(0) + + $group.find('label').on('change', function () { + countChangeEvent++ + }) + + setTimeout(function () { + assert.strictEqual(countChangeEvent, 1, 'onchange event fired only once') + done() + }, 5) + + $btn[0].click() + }) + QUnit.test('should check for closest matching toggle', function (assert) { - assert.expect(12) + assert.expect(18) var groupHTML = '
' + '