├── . browserslistrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ ├── changelog.yml │ ├── local-tests.yml │ └── remote-tests.yml ├── .gitignore ├── .stylelintrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── SECURITY.md ├── dist ├── css │ ├── joomla-alert.css │ ├── joomla-alert.min.css │ ├── joomla-collapse.css │ ├── joomla-collapse.min.css │ ├── joomla-dropdown.css │ ├── joomla-dropdown.min.css │ ├── joomla-modal.css │ ├── joomla-modal.min.css │ ├── joomla-tab.css │ ├── joomla-tab.min.css │ ├── joomla-tip.css │ └── joomla-tip.min.css └── js │ ├── joomla-alert-es5.js │ ├── joomla-alert-es5.min.js │ ├── joomla-alert.js │ ├── joomla-alert.min.js │ ├── joomla-collapse-es5.js │ ├── joomla-collapse-es5.min.js │ ├── joomla-collapse.js │ ├── joomla-collapse.min.js │ ├── joomla-dropdown-es5.js │ ├── joomla-dropdown-es5.min.js │ ├── joomla-dropdown.js │ ├── joomla-dropdown.min.js │ ├── joomla-modal-es5.js │ ├── joomla-modal-es5.min.js │ ├── joomla-modal.js │ ├── joomla-modal.min.js │ ├── joomla-tab-es5.js │ ├── joomla-tab-es5.min.js │ ├── joomla-tab.js │ ├── joomla-tab.min.js │ ├── joomla-tip-es5.js │ ├── joomla-tip-es5.min.js │ ├── joomla-tip.js │ └── joomla-tip.min.js ├── docs ├── .nojekyll ├── README.md ├── _coverpage.md ├── _images │ └── 80px-Joomla_logo.png ├── _media │ ├── ce-loader.js │ ├── css │ │ ├── joomla-alert.css │ │ ├── joomla-alert.min.css │ │ ├── joomla-collapse.css │ │ ├── joomla-collapse.min.css │ │ ├── joomla-dropdown.css │ │ ├── joomla-dropdown.min.css │ │ ├── joomla-modal.css │ │ ├── joomla-modal.min.css │ │ ├── joomla-panels.css │ │ ├── joomla-panels.min.css │ │ ├── joomla-tab.css │ │ ├── joomla-tab.min.css │ │ ├── joomla-tip.css │ │ └── joomla-tip.min.css │ ├── docs-overrides.css │ ├── favicon.ico │ ├── icon.svg │ ├── js │ │ ├── joomla-alert-es5.js │ │ ├── joomla-alert-es5.min.js │ │ ├── joomla-alert.js │ │ ├── joomla-alert.min.js │ │ ├── joomla-collapse-es5.js │ │ ├── joomla-collapse-es5.min.js │ │ ├── joomla-collapse.js │ │ ├── joomla-collapse.min.js │ │ ├── joomla-dropdown-es5.js │ │ ├── joomla-dropdown-es5.min.js │ │ ├── joomla-dropdown.js │ │ ├── joomla-dropdown.min.js │ │ ├── joomla-modal-es5.js │ │ ├── joomla-modal-es5.min.js │ │ ├── joomla-modal.js │ │ ├── joomla-modal.min.js │ │ ├── joomla-panels-es5.js │ │ ├── joomla-panels-es5.min.js │ │ ├── joomla-panels.js │ │ ├── joomla-panels.min.js │ │ ├── joomla-tab-es5.js │ │ ├── joomla-tab-es5.min.js │ │ ├── joomla-tab.js │ │ ├── joomla-tab.min.js │ │ ├── joomla-tip-es5.js │ │ ├── joomla-tip-es5.min.js │ │ ├── joomla-tip.js │ │ └── joomla-tip.min.js │ └── vue.css ├── _sidebar.md ├── alert.md ├── bootstrap-demo.html ├── collapse.md ├── dropdown.md ├── foundation-demo.html ├── index.html ├── modal.md ├── quickstart.md ├── styles.md ├── sw.js ├── tab.md ├── tip.md └── uikit-demo.html ├── karma-ci.conf.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── renovate.json ├── rollup.config.mjs ├── src ├── js │ ├── alert │ │ └── alert.js │ ├── collapse │ │ └── collapse.js │ ├── dropdown │ │ └── dropdown.js │ ├── modal │ │ └── modal.js │ ├── tab │ │ ├── tab-element.js │ │ └── tab.js │ └── tip │ │ └── tip.js └── scss │ ├── _variables.scss │ ├── alert │ └── alert.scss │ ├── collapse │ └── collapse.scss │ ├── dropdown │ └── dropdown.scss │ ├── modal │ └── modal.scss │ ├── tab │ └── tab.scss │ └── tip │ └── tip.scss └── tests ├── alert ├── alert.html └── test.js └── tab ├── tab.html └── test.js /. browserslistrc: -------------------------------------------------------------------------------- 1 | # https://github.com/browserslist/browserslist#readme 2 | 3 | >= 0.5% 4 | last 2 major versions 5 | not dead 6 | Chrome >= 60 7 | Firefox >= 60 8 | Firefox ESR 9 | iOS >= 12 10 | Safari >= 12 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | insert_final_newline = true 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /demo/** 2 | /dist/** 3 | /docs/** 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "browser": true 5 | }, 6 | "rules": { 7 | "class-methods-use-this": "off", 8 | "import/prefer-default-export": "off", 9 | "import/extensions": "off", 10 | "no-plusplus": [ 11 | "error", 12 | { 13 | "allowForLoopAfterthoughts": true 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | # This action requires that any PR targeting the master branch should touch at 2 | # least one CHANGELOG file. If a CHANGELOG entry is not required, add the "Skip 3 | # Changelog" label to disable this action. 4 | 5 | name: changelog 6 | 7 | on: 8 | pull_request: 9 | types: [opened, synchronize, reopened, labeled, unlabeled] 10 | branches: 11 | - master 12 | 13 | jobs: 14 | changelog: 15 | runs-on: ubuntu-latest 16 | if: "!contains(github.event.pull_request.labels.*.name, 'Skip Changelog')" 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Check for CHANGELOG changes 22 | run: | 23 | # Only the latest commit of the feature branch is available 24 | # automatically (see https://github.com/webcomponents/polyfills). To 25 | # diff with the base branch, we need to fetch that too (and we only 26 | # need its latest commit). 27 | git fetch origin ${{ github.base_ref }} --depth=1 28 | if [[ $(git diff --name-only FETCH_HEAD | grep CHANGELOG) ]] 29 | then 30 | echo "A CHANGELOG was modified. Looks good!" 31 | else 32 | echo "No CHANGELOG was modified." 33 | echo "Please add a CHANGELOG entry, or add the \"Skip Changelog\" label if not required." 34 | false 35 | fi 36 | -------------------------------------------------------------------------------- /.github/workflows/local-tests.yml: -------------------------------------------------------------------------------- 1 | # This action will run the tests locally using Chrome 2 | name: localtests 3 | 4 | on: 5 | pull_request: 6 | types: [opened, synchronize, reopened, labeled, unlabeled] 7 | branches: 8 | - master 9 | 10 | jobs: 11 | localtests: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - uses: actions/setup-node@v1 17 | name: Set up NodeJS 18 | with: 19 | node-version: 18 20 | 21 | - name: Install 22 | run: npm install 23 | 24 | # Run the tests locally 25 | - name: Run the tests locally 26 | run: npm run test 27 | -------------------------------------------------------------------------------- /.github/workflows/remote-tests.yml: -------------------------------------------------------------------------------- 1 | name: SauceLabs Browser Testing 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | types: [closed] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - uses: actions/setup-node@v3 18 | name: Set up NodeJS 19 | with: 20 | node-version: 18 21 | 22 | - name: Install 23 | run: npm install 24 | 25 | # Sause Labs part 26 | - uses: saucelabs/sauce-connect-action@v2.3.4 27 | with: 28 | username: ${{ secrets.SAUCE_USERNAME }} 29 | accesskey: ${{ secrets.SAUCE_ACCESS_KEY }} 30 | tunnelIdentifier: github-action-tunnel-custom-elements-${{ github.run_id }} 31 | # github-action-tunnel-custom-elements-${process.env.GITHUB_RUN_ID} 32 | 33 | # Run the tests 34 | - name: Run tests in Sauce 35 | run: npm run ci-test 36 | env: 37 | SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }} 38 | SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }} 39 | 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE & System Related Files # 2 | .buildpath 3 | .editorconfig 4 | .project 5 | .settings 6 | .DS_Store 7 | .idea 8 | .vscode 9 | .log 10 | 11 | node_modules/ 12 | !dist/ 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | - Various build tool and github workflow version bumps 10 | - Update all npm packages 11 | - Fix scss lint issues 12 | - Fix javascript lint issues 13 | 14 | ## 0.2.0 15 | - Refactor of the tabs element 16 | - Logic rewritten so the tabs won't be reappended (no more moving elements) 17 | - Added `breakpoint` attribute for controling the transition from tabs/accordion 18 | - Added tests 19 | 20 | ## 0.1.0 21 | - Rewrote the scss to use CSS custom properties than preprocessed SCSS variables 22 | - Added animations for entry/exit of the element 23 | 24 | ## 0.0.43/0.0.44 25 | *Note 0.0.43 was released with the dist folder still from 0.0.42. Please do not use the release and instead use 0.0.44* 26 | 27 | - Refactor build tools to rollup from Grunt 28 | - Refactor tests to use karma from WCT Tester 29 | - Add type="button" to the alert close button 30 | - Refactor of the alert element 31 | - Removed `acknowledge` attribute 32 | - Removed `href` attribute 33 | - Added `close-text` attribute. This should be used to load the close button with multilingual text 34 | 35 | ## 0.0.41/0.0.42 36 | *Note 0.0.41 was released with the dist folder still from 0.0.40. Please do not use the release and instead use 0.0.42* 37 | 38 | - Moved tests from Travis to GitHub Actions 39 | - Moved last dependencies to be devDependencies 40 | - Documentation cleanup/improvements 41 | - Remove dependencies on Bower 42 | - No longer ship with Web Component Polyfills in the dist folder. These were a clone of existing polyfills that 43 | can be found [here](https://github.com/webcomponents/polyfills/) and we recommend you pick a version of the polyfills 44 | appropriate for your minimum browser requirements and load it async using the loader tool. 45 | - Optimise SCSS 46 | - Fix wrong event target in tabs when child is a HTML tag 47 | 48 | ## 0.0.40 49 | 0.0.39 still had the compiled assets from 0.0.38. This fixes that distribution issue. 50 | 51 | ## 0.0.39 52 | - Add support for prefers-reduced-motion in alerts 53 | - Allow toggling accordion on click in the tab custom element 54 | - Dependency updates 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Joomla UI custom elements 2 | 3 | Build Status 4 | --------------------- 5 | 6 | | SauceLabs tests | GreenKeeper | Webcomponents.org | 7 | | ------------- | ------------- | ------------- | 8 | | [![Sauce Test Status](https://app.saucelabs.com/buildstatus/joomla-custom-elements)](https://app.saucelabs.com/u/joomla-custom-elements) | [![Greenkeeper badge](https://badges.greenkeeper.io/joomla-projects/custom-elements.svg)](https://greenkeeper.io/) | [![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/joomla-projects/custom-elements) | 9 | 10 | | Sauce Labs | 11 | | ------------- | 12 | | [![Browser Matrix](https://app.saucelabs.com/browser-matrix/joomla-custom-elements.svg)](https://app.saucelabs.com/u/joomla-custom-elements) | 13 | 14 | ### UI components using modern technologies 15 | 16 | This is a collection of all the components that Joomla is using. They are developed with the new W3C standard: custom elements. Each component is using plain and optimized javascript for performance. Also the HTML markup (wherever possible) is reduced to offer a great benefit for front end developers). 17 | 18 | ### Using the NPM power 19 | 20 | You can install this package by using NPM: 21 | ```bash 22 | $ npm i joomla-ui-custom-elements 23 | ``` 24 | 25 | ### Configuration 26 | 27 | The prefix of all the elements is configuarable. To do so duplicate the file `settings.yaml` and name the new file as `settings-custom.yaml`. Open the file in your editor and change the prefix to your taste. (It needs to be one word - check the W3C speifications for valid custom element naming). 28 | Build your custom elements by executing: 29 | ```bash 30 | $ grunt 31 | ``` 32 | The folder named `dist` contains all your elements. 33 | 34 | ### Usage 35 | 36 | For each component that you need to have available in your page you need to add the custom element in the head of the document: 37 | ```html 38 | 39 | ``` 40 | 41 | ### Tests 42 | 43 | Once again we are using the great tools from the polymer team here! 44 | You will need `wct` (web component tester) installed globally. To do so just run `npm install web-component-tester -g`. 45 | You might need to run that command as sudo! 46 | After that, in the root folder of this project just run `wct` and see the status of the tests... 47 | 48 | The default setup is based on MacOS system and looking for Chrome, Firefox and Safari browsers, you can change this by editing line 5 of https://github.com/joomla-projects/custom-elements/blob/master/wct.conf.json#L5 49 | 50 | ### Browser support 51 | 52 | Although all the major browsers are **committed** to support custom elements some of the **all green browsers** do need a polyfill. The polyfills can be found in the dist folder and are created by the Polymer team (Polymer is a Google project). 53 | The repo for the actual polyfill is: https://github.com/webcomponents/webcomponentsjs 54 | 55 | ### Documentation 56 | Fully documented [here](https://joomla-projects.github.io/custom-elements/) 57 | 58 | ### License 59 | 60 | The library is released under the [GPL license](LICENSE) 61 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policies and Procedures 2 | 3 | This document outlines security procedures and policies for the `Joomla! Project`. 4 | 5 | * [Reporting a Bug](#reporting-a-bug) 6 | * [Response Handling](#response-handling) 7 | * [Security Announcement Policy](#security-announcement-policy) 8 | * [Further Details on the Joomla! Security Policies](https://security.joomla.org) 9 | 10 | ## Reporting a Bug 11 | 12 | The `Joomla` team and community take all security bugs in `Joomla` seriously. The Joomla! Security Strike Team (JSST) oversees the project's security issues and follows some specific procedures when dealing with these issues. 13 | 14 | If you find a possible vulnerability, please report it to the JSST using the [online form](https://developer.joomla.org/security/contact-the-team.html) or via email at security@joomla.org 15 | 16 | We maintain a list of [GPG keys and addresses](https://developer.joomla.org/security/gpg-keys.html) for the security@joomla.org address and members of the JSST to allow signed and encrypted communications. 17 | 18 | To report an issue in a Joomla! extension, please submit it to the [Vulnerable Extensions List.](https://vel.joomla.org/submit-vel) 19 | 20 | For support with a site which has been attacked, please visit the [Joomla! Forum.](https://forum.joomla.org/viewforum.php?f=714) 21 | 22 | Thank you for improving the security of `Joomla`. 23 | 24 | ## Response Handling 25 | 26 | The JSST aims to ensure all issues are handled in a timely manner and for clear communication between the team and issue reporters. We have established the following guidelines for responding to issue reports: 27 | 28 | * Within 24 hours every report gets acknowledged 29 | * Within 7 days every report gets a further response stating either 30 | * the issue is closed (and why) 31 | * the issue is still under investigation; if needed, additional information will be requested 32 | * Within 21 days every report must be resolved unless there are exceptional circumstances requiring additional time 33 | 34 | ## Security Announcement Policy 35 | * Verified vulnerabilities will only be publicly announced AFTER a release is issued which fixes the vulnerability. 36 | * All announcements will contain as much information as possible, but will NOT contain step-by-step instructions for the vulnerability. 37 | * The `Joomla! Project` will properly credit individuals and/or organizations who responsibly disclose security issues to the JSST. You can indicate the way you would like to be referred to in the advisory about the vulnerability. Our preference is to use full names. If you do not specify then we will use the contact name associated with the email address the report was received from. You can also request a pseudonym or having your name withheld. 38 | -------------------------------------------------------------------------------- /dist/css/joomla-alert.css: -------------------------------------------------------------------------------- 1 | joomla-alert { 2 | --jui-alert-min-width: 250px; 3 | --jui-alert-padding: .5rem 1.25rem; 4 | --jui-alert-margin: 0 0 1rem 0; 5 | --jui-alert-border: 1px solid transparent; 6 | --jui-alert-border-radius: .25rem; 7 | --jui-alert-animation-duration: .5s; 8 | --jui-alert-animation-timing-function: ease-in-out; 9 | --jui-alert-button-color-dark: #000; 10 | --jui-alert-button-color-light: #fff; 11 | --jui-alert-success-color: #234423; 12 | --jui-alert-success-background-color: #d9e6d9; 13 | --jui-alert-success-border-color: #cadcca; 14 | --jui-alert-success-link-color: #122212; 15 | --jui-alert-info-color: #0c5460; 16 | --jui-alert-info-background-color: #d1ecf1; 17 | --jui-alert-info-border-color: #bee5eb; 18 | --jui-alert-info-link-color: #062c33; 19 | --jui-alert-warning-color: #7d5a29; 20 | --jui-alert-warning-background-color: #fcefdc; 21 | --jui-alert-warning-border-color: #fbe8cd; 22 | --jui-alert-warning-link-color: #573e1c; 23 | --jui-alert-danger-color: #712b29; 24 | --jui-alert-danger-background-color: #f7dddc; 25 | --jui-alert-danger-border-color: #f4cfce; 26 | --jui-alert-danger-link-color: #4c1d1b; 27 | display: block; 28 | min-width: var(--jui-alert-min-width, 250px); 29 | padding: var(--jui-alert-padding, 0.5rem 1.25rem); 30 | margin: var(--jui-alert-margin, 0 0 1rem 0); 31 | border: var(--jui-alert-border, 1px solid transparent); 32 | border-radius: var(--jui-alert-border-radius, 0.25rem); 33 | animation-duration: var(--jui-alert-animation-duration, 0.5s); 34 | animation-timing-function: var(--jui-alert-animation-timing-function, ease-in-out); 35 | } 36 | 37 | joomla-alert .joomla-alert--close { 38 | position: relative; 39 | top: -0.5rem; 40 | right: -1.25rem; 41 | float: right; 42 | padding: 0.2rem 1rem; 43 | font-size: 1.5rem; 44 | font-weight: 700; 45 | line-height: 1; 46 | color: var(--jui-alert-button-color-dark, #000); 47 | text-shadow: 0 1px 0 var(--jui-alert-button-color-light, #fff); 48 | background: transparent; 49 | border: 0; 50 | opacity: 0.5; 51 | } 52 | 53 | joomla-alert .joomla-alert--close:hover, 54 | joomla-alert .joomla-alert--close:focus { 55 | color: var(--jui-alert-button-color-dark, #000); 56 | text-decoration: none; 57 | cursor: pointer; 58 | opacity: 0.75; 59 | } 60 | 61 | joomla-alert[type=success] { 62 | color: var(--jui-alert-success-color, #234423); 63 | background-color: var(--jui-alert-success-background-color, #d9e6d9); 64 | border-color: var(--jui-alert-success-border-color, #cadcca); 65 | } 66 | 67 | joomla-alert[type=success] hr { 68 | border-top-color: var(--jui-alert-success-border-color, #cadcca); 69 | } 70 | 71 | joomla-alert[type=success] .alert-link { 72 | color: var(--jui-alert-success-link-color, #122212); 73 | } 74 | 75 | joomla-alert[type=info] { 76 | color: var(--jui-alert-info-color, #0c5460); 77 | background-color: var(--jui-alert-info-background-color, #d1ecf1); 78 | border-color: var(--jui-alert-info-border-color, #bee5eb); 79 | } 80 | 81 | joomla-alert[type=info] hr { 82 | border-top-color: var(--jui-alert-info-border-color, #bee5eb); 83 | } 84 | 85 | joomla-alert[type=info] .alert-link { 86 | color: var(--jui-alert-info-link-color, #062c33); 87 | } 88 | 89 | joomla-alert[type=warning] { 90 | color: var(--jui-alert-warning-color, #7d5a29); 91 | background-color: var(--jui-alert-warning-background-color, #fcefdc); 92 | border-color: var(--jui-alert-warning-border-color, #fbe8cd); 93 | } 94 | 95 | joomla-alert[type=warning] hr { 96 | border-top-color: var(--jui-alert-warning-border-color, #fbe8cd); 97 | } 98 | 99 | joomla-alert[type=warning] .alert-link { 100 | color: var(--jui-alert-warning-link-color, #573e1c); 101 | } 102 | 103 | joomla-alert[type=danger] { 104 | color: var(--jui-alert-danger-color, #712b29); 105 | background-color: var(--jui-alert-danger-background-color, #f7dddc); 106 | border-color: var(--jui-alert-danger-border-color, #f4cfce); 107 | } 108 | 109 | joomla-alert[type=danger] hr { 110 | border-top-color: var(--jui-alert-danger-border-color, #f4cfce); 111 | } 112 | 113 | joomla-alert[type=danger] .alert-link { 114 | color: var(--jui-alert-danger-link-color, #4c1d1b); 115 | } 116 | 117 | html[dir=rtl] joomla-alert .joomla-alert--close, 118 | html[dir=rtl] joomla-alert .joomla-alert-button--close { 119 | right: auto; 120 | left: -1.25rem; 121 | float: left; 122 | } 123 | 124 | @keyframes joomla-alert-fade-in { 125 | 0% { 126 | opacity: 0; 127 | } 128 | } 129 | @keyframes joomla-alert-fade-out { 130 | 0% { 131 | opacity: 1; 132 | } 133 | 100% { 134 | opacity: 0; 135 | } 136 | } 137 | @media (prefers-reduced-motion: reduce) { 138 | joomla-alert { 139 | animation-duration: 1ms !important; 140 | } 141 | } -------------------------------------------------------------------------------- /dist/css/joomla-alert.min.css: -------------------------------------------------------------------------------- 1 | joomla-alert{--jui-alert-min-width:250px;--jui-alert-padding:.5rem 1.25rem;--jui-alert-margin:0 0 1rem 0;--jui-alert-border:1px solid transparent;--jui-alert-border-radius:.25rem;--jui-alert-animation-duration:.5s;--jui-alert-animation-timing-function:ease-in-out;--jui-alert-button-color-dark:#000;--jui-alert-button-color-light:#fff;--jui-alert-success-color:#234423;--jui-alert-success-background-color:#d9e6d9;--jui-alert-success-border-color:#cadcca;--jui-alert-success-link-color:#122212;--jui-alert-info-color:#0c5460;--jui-alert-info-background-color:#d1ecf1;--jui-alert-info-border-color:#bee5eb;--jui-alert-info-link-color:#062c33;--jui-alert-warning-color:#7d5a29;--jui-alert-warning-background-color:#fcefdc;--jui-alert-warning-border-color:#fbe8cd;--jui-alert-warning-link-color:#573e1c;--jui-alert-danger-color:#712b29;--jui-alert-danger-background-color:#f7dddc;--jui-alert-danger-border-color:#f4cfce;--jui-alert-danger-link-color:#4c1d1b;animation-duration:var(--jui-alert-animation-duration,.5s);animation-timing-function:var(--jui-alert-animation-timing-function,ease-in-out);border:var(--jui-alert-border,1px solid transparent);border-radius:var(--jui-alert-border-radius,.25rem);display:block;margin:var(--jui-alert-margin,0 0 1rem 0);min-width:var(--jui-alert-min-width,250px);padding:var(--jui-alert-padding,.5rem 1.25rem)}joomla-alert .joomla-alert--close{background:transparent;border:0;color:var(--jui-alert-button-color-dark,#000);float:right;font-size:1.5rem;font-weight:700;line-height:1;opacity:.5;padding:.2rem 1rem;position:relative;right:-1.25rem;text-shadow:0 1px 0 var(--jui-alert-button-color-light,#fff);top:-.5rem}joomla-alert .joomla-alert--close:focus,joomla-alert .joomla-alert--close:hover{color:var(--jui-alert-button-color-dark,#000);cursor:pointer;opacity:.75;text-decoration:none}joomla-alert[type=success]{background-color:var(--jui-alert-success-background-color,#d9e6d9);border-color:var(--jui-alert-success-border-color,#cadcca);color:var(--jui-alert-success-color,#234423)}joomla-alert[type=success] hr{border-top-color:var(--jui-alert-success-border-color,#cadcca)}joomla-alert[type=success] .alert-link{color:var(--jui-alert-success-link-color,#122212)}joomla-alert[type=info]{background-color:var(--jui-alert-info-background-color,#d1ecf1);border-color:var(--jui-alert-info-border-color,#bee5eb);color:var(--jui-alert-info-color,#0c5460)}joomla-alert[type=info] hr{border-top-color:var(--jui-alert-info-border-color,#bee5eb)}joomla-alert[type=info] .alert-link{color:var(--jui-alert-info-link-color,#062c33)}joomla-alert[type=warning]{background-color:var(--jui-alert-warning-background-color,#fcefdc);border-color:var(--jui-alert-warning-border-color,#fbe8cd);color:var(--jui-alert-warning-color,#7d5a29)}joomla-alert[type=warning] hr{border-top-color:var(--jui-alert-warning-border-color,#fbe8cd)}joomla-alert[type=warning] .alert-link{color:var(--jui-alert-warning-link-color,#573e1c)}joomla-alert[type=danger]{background-color:var(--jui-alert-danger-background-color,#f7dddc);border-color:var(--jui-alert-danger-border-color,#f4cfce);color:var(--jui-alert-danger-color,#712b29)}joomla-alert[type=danger] hr{border-top-color:var(--jui-alert-danger-border-color,#f4cfce)}joomla-alert[type=danger] .alert-link{color:var(--jui-alert-danger-link-color,#4c1d1b)}html[dir=rtl] joomla-alert .joomla-alert--close,html[dir=rtl] joomla-alert .joomla-alert-button--close{float:left;left:-1.25rem;right:auto}@keyframes joomla-alert-fade-in{0%{opacity:0}}@keyframes joomla-alert-fade-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){joomla-alert{animation-duration:1ms!important}} -------------------------------------------------------------------------------- /dist/css/joomla-collapse.css: -------------------------------------------------------------------------------- 1 | joomla-collapse[state=closed] { 2 | display: none; 3 | } 4 | joomla-collapse[state=open] { 5 | display: block; 6 | } -------------------------------------------------------------------------------- /dist/css/joomla-collapse.min.css: -------------------------------------------------------------------------------- 1 | joomla-collapse[state=closed]{display:none}joomla-collapse[state=open]{display:block} -------------------------------------------------------------------------------- /dist/css/joomla-dropdown.css: -------------------------------------------------------------------------------- 1 | joomla-dropdown { 2 | position: absolute; 3 | top: 30px; 4 | left: 0; 5 | z-index: 1000; 6 | box-sizing: border-box; 7 | display: none; 8 | min-width: 10rem; 9 | margin-top: 0.5rem; 10 | font-size: 1rem; 11 | text-align: left; 12 | list-style: none; 13 | background-color: #fff; 14 | background-clip: padding-box; 15 | border: 1px solid rgba(0, 0, 0, 0.15); 16 | } 17 | joomla-dropdown[expanded] { 18 | display: block; 19 | } 20 | joomla-dropdown .dropdown-item { 21 | display: block; 22 | padding: 0.5rem 0.75rem; 23 | clear: both; 24 | font-weight: 400; 25 | color: #212529; 26 | text-align: inherit; 27 | white-space: nowrap; 28 | background-color: transparent; 29 | border: 0; 30 | } 31 | joomla-dropdown .dropdown-item:hover, joomla-dropdown .dropdown-item:focus { 32 | color: #fff; 33 | text-decoration: none; 34 | cursor: pointer; 35 | background: #495057; 36 | } 37 | 38 | .joomla-dropdown-container { 39 | position: relative; 40 | display: inline-flex; 41 | vertical-align: middle; 42 | } 43 | 44 | html[dir=rtl] joomla-dropdown { 45 | right: 0; 46 | left: auto; 47 | } -------------------------------------------------------------------------------- /dist/css/joomla-dropdown.min.css: -------------------------------------------------------------------------------- 1 | joomla-dropdown{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.15);box-sizing:border-box;display:none;font-size:1rem;left:0;list-style:none;margin-top:.5rem;min-width:10rem;position:absolute;text-align:left;top:30px;z-index:1000}joomla-dropdown[expanded]{display:block}joomla-dropdown .dropdown-item{background-color:transparent;border:0;clear:both;color:#212529;display:block;font-weight:400;padding:.5rem .75rem;text-align:inherit;white-space:nowrap}joomla-dropdown .dropdown-item:focus,joomla-dropdown .dropdown-item:hover{background:#495057;color:#fff;cursor:pointer;text-decoration:none}.joomla-dropdown-container{display:inline-flex;position:relative;vertical-align:middle}html[dir=rtl] joomla-dropdown{left:auto;right:0} -------------------------------------------------------------------------------- /dist/css/joomla-modal.css: -------------------------------------------------------------------------------- 1 | joomla-modal { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | z-index: 1050; 8 | box-sizing: inherit; 9 | display: none; 10 | max-width: 500px; 11 | margin: 10px auto; 12 | overflow: hidden; 13 | border-radius: 5px; 14 | outline: 0; 15 | } 16 | joomla-modal.jviewport-width10 { 17 | width: 10vw; 18 | margin-left: -5vw; 19 | } 20 | joomla-modal.jviewport-width20 { 21 | width: 20vw; 22 | margin-left: -10vw; 23 | } 24 | joomla-modal.jviewport-width30 { 25 | width: 30vw; 26 | margin-left: -15vw; 27 | } 28 | joomla-modal.jviewport-width40 { 29 | width: 40vw; 30 | margin-left: -20vw; 31 | } 32 | joomla-modal.jviewport-width50 { 33 | width: 50vw; 34 | margin-left: -25vw; 35 | } 36 | joomla-modal.jviewport-width60 { 37 | width: 60vw; 38 | margin-left: -30vw; 39 | } 40 | joomla-modal.jviewport-width70 { 41 | width: 70vw; 42 | margin-left: -35vw; 43 | } 44 | joomla-modal.jviewport-width80 { 45 | width: 80vw; 46 | margin-left: -40vw; 47 | } 48 | joomla-modal.jviewport-width90 { 49 | width: 90vw; 50 | margin-left: -45vw; 51 | } 52 | joomla-modal.jviewport-width100 { 53 | width: 100vw; 54 | margin-left: -50vw; 55 | } 56 | joomla-modal.show { 57 | display: block; 58 | } 59 | joomla-modal .joomla-modal-dialog { 60 | position: relative; 61 | display: flex; 62 | flex-direction: column; 63 | background-color: #fff; 64 | background-clip: padding-box; 65 | border: 1px solid rgba(0, 0, 0, 0.2); 66 | border-radius: 0.3rem; 67 | outline: 0; 68 | } 69 | joomla-modal .joomla-modal-dialog.fade { 70 | opacity: 0; 71 | transition: opacity 0.15s linear; 72 | } 73 | joomla-modal .joomla-modal-dialog.fade.show { 74 | opacity: 1; 75 | } 76 | joomla-modal .joomla-modal-dialog header { 77 | display: flex; 78 | align-items: center; 79 | justify-content: space-between; 80 | padding: 15px; 81 | border-bottom: 1px solid #e9ecef; 82 | } 83 | joomla-modal .joomla-modal-dialog header button { 84 | float: right; 85 | padding: 0; 86 | font-size: 1.5rem; 87 | font-weight: 700; 88 | line-height: 1; 89 | color: #000; 90 | text-shadow: 0 1px 0 #fff; 91 | cursor: pointer; 92 | background: 0 0; 93 | border: 0; 94 | opacity: 0.5; 95 | -webkit-appearance: none; 96 | -moz-appearance: none; 97 | appearance: none; 98 | } 99 | joomla-modal .joomla-modal-dialog header h5 { 100 | margin-bottom: 0; 101 | font-size: 1.25rem; 102 | line-height: 1.5; 103 | } 104 | joomla-modal .joomla-modal-dialog section { 105 | position: relative; 106 | flex: 1 1 auto; 107 | padding: 15px; 108 | } 109 | joomla-modal .joomla-modal-dialog section.jviewport-height10 { 110 | height: 10vh; 111 | } 112 | joomla-modal .joomla-modal-dialog section.jviewport-height20 { 113 | height: 20vh; 114 | } 115 | joomla-modal .joomla-modal-dialog section.jviewport-height30 { 116 | height: 30vh; 117 | } 118 | joomla-modal .joomla-modal-dialog section.jviewport-height40 { 119 | height: 40vh; 120 | } 121 | joomla-modal .joomla-modal-dialog section.jviewport-height50 { 122 | height: 50vh; 123 | } 124 | joomla-modal .joomla-modal-dialog section.jviewport-height60 { 125 | height: 60vh; 126 | } 127 | joomla-modal .joomla-modal-dialog section.jviewport-height70 { 128 | height: 70vh; 129 | } 130 | joomla-modal .joomla-modal-dialog section.jviewport-height80 { 131 | height: 80vh; 132 | } 133 | joomla-modal .joomla-modal-dialog section.jviewport-height90 { 134 | height: 90vh; 135 | } 136 | joomla-modal .joomla-modal-dialog section.jviewport-height100 { 137 | height: 100vh; 138 | } 139 | joomla-modal .joomla-modal-dialog section[class^=jviewport-height], 140 | joomla-modal .joomla-modal-dialog section[class*=jviewport-height] { 141 | max-height: none; 142 | } 143 | joomla-modal .joomla-modal-dialog footer { 144 | display: flex; 145 | align-items: center; 146 | justify-content: flex-end; 147 | padding: 15px; 148 | border-top: 1px solid #e9ecef; 149 | } 150 | joomla-modal .joomla-modal-dialog footer .btn { 151 | margin-left: 10px; 152 | } 153 | 154 | .modal-backdrop.show { 155 | opacity: 0.5; 156 | } 157 | 158 | .modal-backdrop { 159 | position: fixed; 160 | top: 0; 161 | right: 0; 162 | bottom: 0; 163 | left: 0; 164 | z-index: 1040; 165 | background-color: #000; 166 | } -------------------------------------------------------------------------------- /dist/css/joomla-modal.min.css: -------------------------------------------------------------------------------- 1 | joomla-modal{border-radius:5px;bottom:0;box-sizing:inherit;display:none;left:0;margin:10px auto;max-width:500px;outline:0;overflow:hidden;position:fixed;right:0;top:0;z-index:1050}joomla-modal.jviewport-width10{margin-left:-5vw;width:10vw}joomla-modal.jviewport-width20{margin-left:-10vw;width:20vw}joomla-modal.jviewport-width30{margin-left:-15vw;width:30vw}joomla-modal.jviewport-width40{margin-left:-20vw;width:40vw}joomla-modal.jviewport-width50{margin-left:-25vw;width:50vw}joomla-modal.jviewport-width60{margin-left:-30vw;width:60vw}joomla-modal.jviewport-width70{margin-left:-35vw;width:70vw}joomla-modal.jviewport-width80{margin-left:-40vw;width:80vw}joomla-modal.jviewport-width90{margin-left:-45vw;width:90vw}joomla-modal.jviewport-width100{margin-left:-50vw;width:100vw}joomla-modal.show{display:block}joomla-modal .joomla-modal-dialog{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;display:flex;flex-direction:column;outline:0;position:relative}joomla-modal .joomla-modal-dialog.fade{opacity:0;transition:opacity .15s linear}joomla-modal .joomla-modal-dialog.fade.show{opacity:1}joomla-modal .joomla-modal-dialog header{align-items:center;border-bottom:1px solid #e9ecef;display:flex;justify-content:space-between;padding:15px}joomla-modal .joomla-modal-dialog header button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:0 0;border:0;color:#000;cursor:pointer;float:right;font-size:1.5rem;font-weight:700;line-height:1;opacity:.5;padding:0;text-shadow:0 1px 0 #fff}joomla-modal .joomla-modal-dialog header h5{font-size:1.25rem;line-height:1.5;margin-bottom:0}joomla-modal .joomla-modal-dialog section{flex:1 1 auto;padding:15px;position:relative}joomla-modal .joomla-modal-dialog section.jviewport-height10{height:10vh}joomla-modal .joomla-modal-dialog section.jviewport-height20{height:20vh}joomla-modal .joomla-modal-dialog section.jviewport-height30{height:30vh}joomla-modal .joomla-modal-dialog section.jviewport-height40{height:40vh}joomla-modal .joomla-modal-dialog section.jviewport-height50{height:50vh}joomla-modal .joomla-modal-dialog section.jviewport-height60{height:60vh}joomla-modal .joomla-modal-dialog section.jviewport-height70{height:70vh}joomla-modal .joomla-modal-dialog section.jviewport-height80{height:80vh}joomla-modal .joomla-modal-dialog section.jviewport-height90{height:90vh}joomla-modal .joomla-modal-dialog section.jviewport-height100{height:100vh}joomla-modal .joomla-modal-dialog section[class*=jviewport-height],joomla-modal .joomla-modal-dialog section[class^=jviewport-height]{max-height:none}joomla-modal .joomla-modal-dialog footer{align-items:center;border-top:1px solid #e9ecef;display:flex;justify-content:flex-end;padding:15px}joomla-modal .joomla-modal-dialog footer .btn{margin-left:10px}.modal-backdrop.show{opacity:.5}.modal-backdrop{background-color:#000;bottom:0;left:0;position:fixed;right:0;top:0;z-index:1040} -------------------------------------------------------------------------------- /dist/css/joomla-tab.css: -------------------------------------------------------------------------------- 1 | joomla-tab { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | joomla-tab[view=tabs] > div[role=tablist] { 7 | display: flex; 8 | padding: 0; 9 | margin: 0; 10 | overflow-x: auto; 11 | overflow-y: hidden; 12 | white-space: nowrap; 13 | list-style: outside none none; 14 | background-color: #f5f5f5; 15 | border-color: #ccc #ccc currentcolor; 16 | border-style: solid solid none; 17 | border-width: 1px 1px 0; 18 | border-radius: 0.25rem 0.25rem 0 0; 19 | -o-border-image: none; 20 | border-image: none; 21 | box-shadow: 0 1px #fff inset, 0 2px 3px -3px rgba(0, 0, 0, 0.15), 0 -4px 0 rgba(0, 0, 0, 0.05) inset, 0 0 3px rgba(0, 0, 0, 0.04); 22 | } 23 | 24 | joomla-tab[view=accordion] > div[role=tablist] { 25 | display: none; 26 | } 27 | 28 | joomla-tab button[role=tab] { 29 | position: relative; 30 | display: block; 31 | padding: 0.75em 1em; 32 | color: #0d1321; 33 | text-decoration: none; 34 | background-color: transparent; 35 | border: unset; 36 | box-shadow: 1px 0 0 rgba(0, 0, 0, 0.05); 37 | -webkit-appearance: none; 38 | -moz-appearance: none; 39 | appearance: none; 40 | } 41 | 42 | joomla-tab button[role=tab][aria-expanded=true], 43 | joomla-tab button[role=tab][aria-selected=true] { 44 | background-color: rgba(0, 0, 0, 0.03); 45 | background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.05) 100%); 46 | border-right: 0 none; 47 | border-left: 0 none; 48 | border-top-left-radius: 0; 49 | border-top-right-radius: 0; 50 | box-shadow: 2px 0 1px -1px rgba(0, 0, 0, 0.08) inset, -2px 0 1px -1px rgba(0, 0, 0, 0.08) inset, 0 1px 0 rgba(0, 0, 0, 0.02) inset; 51 | } 52 | 53 | joomla-tab button[aria-expanded=true]::after, 54 | joomla-tab button[aria-selected=true]::after { 55 | position: absolute; 56 | right: 0; 57 | bottom: -1px; 58 | left: 0; 59 | height: 5px; 60 | content: ""; 61 | background-color: #006898; 62 | opacity: 0.8; 63 | } 64 | 65 | joomla-tab > joomla-tab-element { 66 | position: relative; 67 | display: none; 68 | padding: 15px; 69 | background-color: #fefefe; 70 | border: 1px solid #ccc; 71 | border-radius: 0 0 0.25rem 0.25rem; 72 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.04); 73 | } 74 | 75 | joomla-tab > joomla-tab-element[active] { 76 | display: block; 77 | } 78 | 79 | joomla-tab[orientation=vertical] { 80 | flex-direction: row; 81 | align-items: flex-start; 82 | } 83 | 84 | joomla-tab[orientation=vertical] > div[role=tablist] { 85 | flex-direction: column; 86 | min-width: 30%; 87 | height: auto; 88 | overflow: hidden; 89 | border: 1px solid #ccc; 90 | border-radius: 0.25rem; 91 | box-shadow: none; 92 | } 93 | 94 | joomla-tab[orientation=vertical] > div[role=tablist] button:last-of-type { 95 | border-bottom: 0; 96 | } 97 | 98 | joomla-tab[orientation=vertical] > div[role=tablist] button { 99 | position: relative; 100 | display: block; 101 | padding: 0.75em 1em; 102 | color: #0d1321; 103 | text-decoration: none; 104 | background-color: transparent; 105 | border-bottom: 1px solid #ddd; 106 | box-shadow: none; 107 | -webkit-appearance: none; 108 | -moz-appearance: none; 109 | appearance: none; 110 | } 111 | 112 | joomla-tab[orientation=vertical] > div[role=tablist] button[aria-expanded=true] { 113 | background-color: #fff; 114 | background-image: none; 115 | border-right: 0 none; 116 | border-left: 0 none; 117 | box-shadow: none; 118 | } 119 | 120 | joomla-tab[orientation=vertical] > div[role=tablist] button[aria-expanded=true]::after { 121 | top: 0; 122 | bottom: 0; 123 | left: -1px; 124 | width: 5px; 125 | height: auto; 126 | } 127 | 128 | joomla-tab[orientation=vertical] > joomla-tab-element { 129 | padding: 15px; 130 | border: 0 none; 131 | box-shadow: none; 132 | } 133 | 134 | joomla-tab[view=accordion] { 135 | flex-direction: column; 136 | white-space: normal; 137 | border-radius: 0.25rem; 138 | box-shadow: 0 1px #fff inset, 0 0 3px rgba(0, 0, 0, 0.04); 139 | } 140 | joomla-tab[view=accordion] > button { 141 | position: relative; 142 | display: block; 143 | padding: 0.75em 1em; 144 | color: #0d1321; 145 | text-decoration: none; 146 | background-color: #f5f5f5; 147 | border: unset; 148 | box-shadow: 1px 0 0 rgba(0, 0, 0, 0.05); 149 | -webkit-appearance: none; 150 | -moz-appearance: none; 151 | appearance: none; 152 | } 153 | joomla-tab[view=accordion] > button[aria-expanded=true], joomla-tab[view=accordion] > button:focus { 154 | background-color: rgba(0, 0, 0, 0.03); 155 | background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.05) 100%); 156 | } 157 | 158 | joomla-tab[view=accordion] joomla-tab-element { 159 | display: none; 160 | padding: 15px; 161 | } 162 | 163 | joomla-tab[view=accordion] joomla-tab-element[active] { 164 | display: block; 165 | border-bottom: 1px solid #ddd; 166 | } 167 | 168 | joomla-tab[view=accordion] [active] { 169 | background-color: #fff; 170 | } 171 | 172 | joomla-tab[view=accordion] button { 173 | -webkit-appearance: none; 174 | -moz-appearance: none; 175 | appearance: none; 176 | border-bottom: 1px solid #ddd; 177 | } 178 | 179 | joomla-tab[view=accordion] button[aria-expanded=true]::after { 180 | top: 0; 181 | left: 0; 182 | width: 5px; 183 | height: 100%; 184 | } -------------------------------------------------------------------------------- /dist/css/joomla-tab.min.css: -------------------------------------------------------------------------------- 1 | joomla-tab{display:flex;flex-direction:column}joomla-tab[view=tabs]>div[role=tablist]{background-color:#f5f5f5;border:1px solid #ccc;border-bottom:0;-o-border-image:none;border-image:none;border-radius:.25rem .25rem 0 0;box-shadow:inset 0 1px #fff,0 2px 3px -3px rgba(0,0,0,.15),inset 0 -4px 0 rgba(0,0,0,.05),0 0 3px rgba(0,0,0,.04);display:flex;list-style:none outside none;margin:0;overflow-x:auto;overflow-y:hidden;padding:0;white-space:nowrap}joomla-tab[view=accordion]>div[role=tablist]{display:none}joomla-tab button[role=tab]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:unset;box-shadow:1px 0 0 rgba(0,0,0,.05);color:#0d1321;display:block;padding:.75em 1em;position:relative;text-decoration:none}joomla-tab button[role=tab][aria-expanded=true],joomla-tab button[role=tab][aria-selected=true]{background-color:rgba(0,0,0,.03);background-image:linear-gradient(180deg,transparent,rgba(0,0,0,.05));border-left:0;border-right:0;border-top-left-radius:0;border-top-right-radius:0;box-shadow:inset 2px 0 1px -1px rgba(0,0,0,.08),inset -2px 0 1px -1px rgba(0,0,0,.08),inset 0 1px 0 rgba(0,0,0,.02)}joomla-tab button[aria-expanded=true]:after,joomla-tab button[aria-selected=true]:after{background-color:#006898;bottom:-1px;content:"";height:5px;left:0;opacity:.8;position:absolute;right:0}joomla-tab>joomla-tab-element{background-color:#fefefe;border:1px solid #ccc;border-radius:0 0 .25rem .25rem;box-shadow:0 0 3px rgba(0,0,0,.04);display:none;padding:15px;position:relative}joomla-tab>joomla-tab-element[active]{display:block}joomla-tab[orientation=vertical]{align-items:flex-start;flex-direction:row}joomla-tab[orientation=vertical]>div[role=tablist]{border:1px solid #ccc;border-radius:.25rem;box-shadow:none;flex-direction:column;height:auto;min-width:30%;overflow:hidden}joomla-tab[orientation=vertical]>div[role=tablist] button:last-of-type{border-bottom:0}joomla-tab[orientation=vertical]>div[role=tablist] button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border-bottom:1px solid #ddd;box-shadow:none;color:#0d1321;display:block;padding:.75em 1em;position:relative;text-decoration:none}joomla-tab[orientation=vertical]>div[role=tablist] button[aria-expanded=true]{background-color:#fff;background-image:none;border-left:0;border-right:0;box-shadow:none}joomla-tab[orientation=vertical]>div[role=tablist] button[aria-expanded=true]:after{bottom:0;height:auto;left:-1px;top:0;width:5px}joomla-tab[orientation=vertical]>joomla-tab-element{border:0;box-shadow:none;padding:15px}joomla-tab[view=accordion]{border-radius:.25rem;box-shadow:inset 0 1px #fff,0 0 3px rgba(0,0,0,.04);flex-direction:column;white-space:normal}joomla-tab[view=accordion]>button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#f5f5f5;border:unset;box-shadow:1px 0 0 rgba(0,0,0,.05);color:#0d1321;display:block;padding:.75em 1em;position:relative;text-decoration:none}joomla-tab[view=accordion]>button:focus,joomla-tab[view=accordion]>button[aria-expanded=true]{background-color:rgba(0,0,0,.03);background-image:linear-gradient(180deg,transparent,rgba(0,0,0,.05))}joomla-tab[view=accordion] joomla-tab-element{display:none;padding:15px}joomla-tab[view=accordion] joomla-tab-element[active]{border-bottom:1px solid #ddd;display:block}joomla-tab[view=accordion] [active]{background-color:#fff}joomla-tab[view=accordion] button{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-bottom:1px solid #ddd}joomla-tab[view=accordion] button[aria-expanded=true]:after{height:100%;left:0;top:0;width:5px} -------------------------------------------------------------------------------- /dist/css/joomla-tip.css: -------------------------------------------------------------------------------- 1 | joomla-tip { 2 | position: relative; 3 | display: inline-block; 4 | } 5 | joomla-tip button { 6 | width: 1.6rem; 7 | height: 1.6rem; 8 | font-family: serif; 9 | font-size: 1.4rem; 10 | font-weight: bold; 11 | line-height: 1.4rem; 12 | color: #fff; 13 | background: #1c3d5c; 14 | border: 0; 15 | border-radius: 50%; 16 | } 17 | joomla-tip .toggletip-bubble { 18 | position: absolute; 19 | z-index: 1040; 20 | display: inline-block; 21 | width: 14rem; 22 | padding: 0.5rem 0.8rem; 23 | font-size: 0.9rem; 24 | line-height: 1.2rem; 25 | color: #fff; 26 | background: #222; 27 | border-radius: 0.25rem; 28 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); 29 | transition: all ease-in; 30 | animation-duration: 0.3s; 31 | } 32 | joomla-tip .toggletip-bubble::after { 33 | position: absolute; 34 | top: 0.6rem; 35 | right: 100%; 36 | width: 0; 37 | height: 0; 38 | content: ""; 39 | border-style: solid; 40 | } 41 | joomla-tip .toggletip-bubble.top { 42 | bottom: 100%; 43 | left: 50%; 44 | margin-bottom: 0.6rem; 45 | transform: translate(-50%, 0); 46 | animation-name: toggletip-fadeInTop; 47 | } 48 | joomla-tip .toggletip-bubble.top::after { 49 | top: 100%; 50 | bottom: auto; 51 | left: 50%; 52 | border-color: #222 transparent transparent; 53 | border-width: 6px 6px 0; 54 | transform: translateX(-50%); 55 | } 56 | joomla-tip .toggletip-bubble.left { 57 | top: 50%; 58 | right: 100%; 59 | margin-right: 0.6rem; 60 | transform: translate(0, -50%); 61 | animation-name: toggletip-fadeInLeft; 62 | } 63 | joomla-tip .toggletip-bubble.left::after { 64 | top: 50%; 65 | bottom: auto; 66 | left: 100%; 67 | border-color: transparent transparent transparent #222; 68 | border-width: 6px 0 6px 6px; 69 | transform: translateY(-50%); 70 | } 71 | joomla-tip .toggletip-bubble.right { 72 | top: 50%; 73 | left: 100%; 74 | margin-left: 0.6rem; 75 | transform: translate(0, -50%); 76 | animation-name: toggletip-fadeInRight; 77 | } 78 | joomla-tip .toggletip-bubble.right::after { 79 | top: 50%; 80 | right: 100%; 81 | bottom: auto; 82 | border-color: transparent #222 transparent transparent; 83 | border-width: 6px 6px 6px 0; 84 | transform: translateY(-50%); 85 | } 86 | joomla-tip .toggletip-bubble.bottom { 87 | top: 100%; 88 | left: 50%; 89 | margin-top: 0.6rem; 90 | transform: translate(-50%, 0); 91 | animation-name: toggletip-fadeInBottom; 92 | } 93 | joomla-tip .toggletip-bubble.bottom::after { 94 | top: -6px; 95 | left: 50%; 96 | border-color: transparent transparent #222; 97 | border-width: 0 6px 6px; 98 | transform: translateX(-50%); 99 | } 100 | 101 | @keyframes toggletip-fadeInRight { 102 | from { 103 | opacity: 0; 104 | transform: translate(-10px, -50%); 105 | } 106 | to { 107 | opacity: 1; 108 | transform: translate(0, -50%); 109 | } 110 | } 111 | @keyframes toggletip-fadeInLeft { 112 | from { 113 | opacity: 0; 114 | transform: translate(10px, -50%); 115 | } 116 | to { 117 | opacity: 1; 118 | transform: translate(0, -50%); 119 | } 120 | } 121 | @keyframes toggletip-fadeInTop { 122 | from { 123 | opacity: 0; 124 | transform: translate(-50%, 10px); 125 | } 126 | to { 127 | opacity: 1; 128 | transform: translate(-50%, 0); 129 | } 130 | } 131 | @keyframes toggletip-fadeInBottom { 132 | from { 133 | opacity: 0; 134 | transform: translate(-50%, -10px); 135 | } 136 | to { 137 | opacity: 1; 138 | transform: translate(-50%, 0); 139 | } 140 | } -------------------------------------------------------------------------------- /dist/css/joomla-tip.min.css: -------------------------------------------------------------------------------- 1 | joomla-tip{display:inline-block;position:relative}joomla-tip button{background:#1c3d5c;border:0;border-radius:50%;color:#fff;font-family:serif;font-size:1.4rem;font-weight:700;height:1.6rem;line-height:1.4rem;width:1.6rem}joomla-tip .toggletip-bubble{animation-duration:.3s;background:#222;border-radius:.25rem;box-shadow:0 0 5px rgba(0,0,0,.4);color:#fff;display:inline-block;font-size:.9rem;line-height:1.2rem;padding:.5rem .8rem;position:absolute;transition:all ease-in;width:14rem;z-index:1040}joomla-tip .toggletip-bubble:after{border-style:solid;content:"";height:0;position:absolute;right:100%;top:.6rem;width:0}joomla-tip .toggletip-bubble.top{animation-name:toggletip-fadeInTop;bottom:100%;left:50%;margin-bottom:.6rem;transform:translate(-50%)}joomla-tip .toggletip-bubble.top:after{border-color:#222 transparent transparent;border-width:6px 6px 0;bottom:auto;left:50%;top:100%;transform:translateX(-50%)}joomla-tip .toggletip-bubble.left{animation-name:toggletip-fadeInLeft;margin-right:.6rem;right:100%;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.left:after{border-color:transparent transparent transparent #222;border-width:6px 0 6px 6px;bottom:auto;left:100%;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.right{animation-name:toggletip-fadeInRight;left:100%;margin-left:.6rem;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.right:after{border-color:transparent #222 transparent transparent;border-width:6px 6px 6px 0;bottom:auto;right:100%;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.bottom{animation-name:toggletip-fadeInBottom;left:50%;margin-top:.6rem;top:100%;transform:translate(-50%)}joomla-tip .toggletip-bubble.bottom:after{border-color:transparent transparent #222;border-width:0 6px 6px;left:50%;top:-6px;transform:translateX(-50%)}@keyframes toggletip-fadeInRight{0%{opacity:0;transform:translate(-10px,-50%)}to{opacity:1;transform:translateY(-50%)}}@keyframes toggletip-fadeInLeft{0%{opacity:0;transform:translate(10px,-50%)}to{opacity:1;transform:translateY(-50%)}}@keyframes toggletip-fadeInTop{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}@keyframes toggletip-fadeInBottom{0%{opacity:0;transform:translate(-50%,-10px)}to{opacity:1;transform:translate(-50%)}} -------------------------------------------------------------------------------- /dist/js/joomla-alert.min.js: -------------------------------------------------------------------------------- 1 | class t extends HTMLElement{constructor(){super(),this.close=this.close.bind(this),this.destroyCloseButton=this.destroyCloseButton.bind(this),this.createCloseButton=this.createCloseButton.bind(this),this.onMutation=this.onMutation.bind(this),this.observer=new MutationObserver(this.onMutation),this.observer.observe(this,{attributes:!1,childList:!0,subtree:!0}),this.addEventListener("animationend",(t=>{"joomla-alert-fade-in"===t.animationName&&t.target===this&&(this.dispatchEvent(new CustomEvent("joomla.alert.shown")),this.style.removeProperty("animationName"))})),this.addEventListener("animationend",(t=>{"joomla-alert-fade-out"===t.animationName&&t.target===this&&(this.dispatchEvent(new CustomEvent("joomla.alert.closed")),this.remove())}))}static get observedAttributes(){return["type","role","dismiss","auto-dismiss","close-text"]}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get role(){return this.getAttribute("role")}set role(t){this.setAttribute("role",t)}get closeText(){return this.getAttribute("close-text")}set closeText(t){this.setAttribute("close-text",t)}get dismiss(){return this.getAttribute("dismiss")}set dismiss(t){this.setAttribute("dismiss",t)}get autodismiss(){return this.getAttribute("auto-dismiss")}set autodismiss(t){this.setAttribute("auto-dismiss",t)}connectedCallback(){this.dispatchEvent(new CustomEvent("joomla.alert.show")),this.style.animationName="joomla-alert-fade-in",this.type&&["info","warning","danger","success"].includes(this.type)||this.setAttribute("type","info"),this.role&&["alert","alertdialog"].includes(this.role)||this.setAttribute("role","alert"),this.firstElementChild&&"BUTTON"===this.firstElementChild.tagName&&(this.button=this.firstElementChild,this.button.classList.contains("joomla-alert--close")&&this.button.classList.add("joomla-alert--close"),""===this.button.innerHTML&&(this.button.innerHTML=''),this.button.hasAttribute("aria-label")||this.button.setAttribute("aria-label",this.closeText)),this.hasAttribute("dismiss")&&!this.button&&this.createCloseButton(),this.hasAttribute("auto-dismiss")&&this.autoDismiss()}disconnectedCallback(){this.button&&this.button.removeEventListener("click",this.close),this.observer.disconnect()}attributeChangedCallback(t,e,s){switch(t){case"type":(!s||s&&-1===["info","warning","danger","success"].indexOf(s))&&(this.type="info");break;case"role":(!s||s&&-1===["alert","alertdialog"].indexOf(s))&&(this.role="alert");break;case"dismiss":s&&""!==s||e&&""!==e?this.button&&"false"===s?this.destroyCloseButton():this.button||"false"===s||this.createCloseButton():this.button&&!this.hasAttribute("dismiss")?this.destroyCloseButton():!this.button&&this.hasAttribute("dismiss")&&this.createCloseButton();break;case"close-text":s&&s===e||this.button&&this.button.setAttribute("aria-label",s);break;case"auto-dismiss":this.autoDismiss()}}onMutation(t){for(const e of t)"childList"===e.type&&e.addedNodes.length&&this.button&&this.firstElementChild!==this.button&&this.prepend(this.button)}close(){this.dispatchEvent(new CustomEvent("joomla.alert.close")),this.style.animationName="joomla-alert-fade-out"}createCloseButton(){this.button=document.createElement("button"),this.button.setAttribute("type","button"),this.button.classList.add("joomla-alert--close"),this.button.innerHTML='',this.button.setAttribute("aria-label",this.closeText),this.insertAdjacentElement("afterbegin",this.button),this.button.addEventListener("click",this.close)}destroyCloseButton(){this.button&&(this.button.removeEventListener("click",this.close),this.button.parentNode.removeChild(this.button),this.button=null)}autoDismiss(){const t=parseInt(this.getAttribute("auto-dismiss"),10);setTimeout(this.close,t>=10?t:3e3)}}customElements.get("joomla-alert")||customElements.define("joomla-alert",t); 2 | -------------------------------------------------------------------------------- /dist/js/joomla-collapse-es5.min.js: -------------------------------------------------------------------------------- 1 | function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){for(var n=0;n { 18 | if (!self.state || (self.state && self.state === 'closed')) { 19 | self.state = 'closed'; 20 | element.setAttribute('aria-expanded', 'false'); 21 | element.setAttribute('aria-controls', self.id); 22 | } else { 23 | element.setAttribute('aria-expanded', 'true'); 24 | element.setAttribute('aria-controls', self.id); 25 | } 26 | 27 | element.addEventListener('click', (event) => { 28 | let colId = ''; 29 | if (!event.target.hasAttribute('data-target')) colId = event.target.getAttribute('href').replace('#', ''); 30 | if (!event.target.hasAttribute('href')) colId = event.target.getAttribute('data-target').replace('#', ''); 31 | event.preventDefault(); 32 | event.stopPropagation(); 33 | document.getElementById(colId).toggle(); 34 | }); 35 | }); 36 | } 37 | 38 | disconnectedCallback() { 39 | let linked = document.querySelector(`[href="#${this.id}"]`); 40 | if (!linked) linked = document.querySelector(`[data-target="#${this.id}"]`); 41 | if (linked) { 42 | linked.removeEventListener('click', this); 43 | } 44 | } 45 | 46 | attributeChangedCallback(attr, oldValue, newValue) { 47 | const linked = document.querySelector(`[href="#${this.id}"]`); 48 | switch (attr) { 49 | case 'state': 50 | if (newValue === 'closed') { 51 | linked.setAttribute('aria-expanded', 'false'); 52 | } else if (newValue === 'open') { 53 | linked.setAttribute('aria-expanded', 'true'); 54 | } 55 | break; 56 | } 57 | } 58 | 59 | toggle() { 60 | let linked = document.querySelector(`[href="#${this.id}"]`); 61 | if (!linked) linked = document.querySelector(`[data-target="#${this.id}"]`); 62 | if (this.state === 'closed') { 63 | this.state = 'open'; 64 | linked.setAttribute('aria-expanded', 'true'); 65 | } else { 66 | this.state = 'closed'; 67 | linked.setAttribute('aria-expanded', 'false'); 68 | } 69 | } 70 | }); 71 | -------------------------------------------------------------------------------- /dist/js/joomla-collapse.min.js: -------------------------------------------------------------------------------- 1 | customElements.define("joomla-collapse",class extends HTMLElement{static get observedAttributes(){return["state"]}get state(){return this.getAttribute("state")}set state(t){this.setAttribute("state",t)}connectedCallback(){const t=this;if(!this.id)return;[].slice.call(document.querySelectorAll(`[href="#${this.id}"],[data-target="#${this.id}"]`)).forEach((e=>{!t.state||t.state&&"closed"===t.state?(t.state="closed",e.setAttribute("aria-expanded","false"),e.setAttribute("aria-controls",t.id)):(e.setAttribute("aria-expanded","true"),e.setAttribute("aria-controls",t.id)),e.addEventListener("click",(t=>{let e="";t.target.hasAttribute("data-target")||(e=t.target.getAttribute("href").replace("#","")),t.target.hasAttribute("href")||(e=t.target.getAttribute("data-target").replace("#","")),t.preventDefault(),t.stopPropagation(),document.getElementById(e).toggle()}))}))}disconnectedCallback(){let t=document.querySelector(`[href="#${this.id}"]`);t||(t=document.querySelector(`[data-target="#${this.id}"]`)),t&&t.removeEventListener("click",this)}attributeChangedCallback(t,e,a){const r=document.querySelector(`[href="#${this.id}"]`);if("state"===t)"closed"===a?r.setAttribute("aria-expanded","false"):"open"===a&&r.setAttribute("aria-expanded","true")}toggle(){let t=document.querySelector(`[href="#${this.id}"]`);t||(t=document.querySelector(`[data-target="#${this.id}"]`)),"closed"===this.state?(this.state="open",t.setAttribute("aria-expanded","true")):(this.state="closed",t.setAttribute("aria-expanded","false"))}}); 2 | -------------------------------------------------------------------------------- /dist/js/joomla-dropdown-es5.min.js: -------------------------------------------------------------------------------- 1 | function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){for(var n=0;n { 26 | if (this.hasAttribute('expanded')) { 27 | this.removeAttribute('expanded'); 28 | event.target.setAttribute('aria-expanded', false); 29 | } else { 30 | this.setAttribute('expanded', ''); 31 | event.target.setAttribute('aria-expanded', true); 32 | } 33 | 34 | document.addEventListener('click', (evt) => { 35 | if (evt.target !== button) { 36 | if (!this.findAncestor(evt.target, 'joomla-dropdown')) { 37 | this.close(); 38 | } 39 | } 40 | }); 41 | 42 | innerLinks.forEach((innerLink) => { 43 | innerLink.addEventListener('click', () => { 44 | this.close(); 45 | }); 46 | }); 47 | }); 48 | } 49 | 50 | /*eslint-disable */ 51 | /* Method to dispatch events */ 52 | dispatchCustomEvent(eventName) { 53 | const OriginalCustomEvent = new CustomEvent(eventName); 54 | OriginalCustomEvent.relatedTarget = this; 55 | this.dispatchEvent(OriginalCustomEvent); 56 | this.removeEventListener(eventName, this); 57 | } 58 | 59 | adoptedCallback(oldDocument, newDocument) { } 60 | 61 | 62 | attributeChangedCallback(attr, oldValue, newValue) { 63 | } 64 | /* eslint-enable */ 65 | 66 | close() { 67 | const button = document.querySelector(`#${this.getAttribute('aria-labelledby')}`); 68 | this.removeAttribute('expanded'); 69 | button.setAttribute('aria-expanded', false); 70 | } 71 | 72 | /* eslint-disable */ 73 | findAncestor(el, tagName) { 74 | while ((el = el.parentElement) && el.nodeName.toLowerCase() !== tagName); 75 | return el; 76 | } 77 | /* eslint-enable */ 78 | } 79 | 80 | customElements.define('joomla-dropdown', JoomlaDropdownElement); 81 | -------------------------------------------------------------------------------- /dist/js/joomla-dropdown.min.js: -------------------------------------------------------------------------------- 1 | class t extends HTMLElement{static get observedAttributes(){return["for"]}get for(){return this.getAttribute("for")}set for(t){this.setAttribute("for",t)}connectedCallback(){this.setAttribute("aria-labelledby",this.for.substring(1));const t=document.querySelector(this.for),e=this.querySelectorAll("a");t.id&&(t.setAttribute("aria-haspopup",!0),t.setAttribute("aria-expanded",!1),t.addEventListener("click",(r=>{this.hasAttribute("expanded")?(this.removeAttribute("expanded"),r.target.setAttribute("aria-expanded",!1)):(this.setAttribute("expanded",""),r.target.setAttribute("aria-expanded",!0)),document.addEventListener("click",(e=>{e.target!==t&&(this.findAncestor(e.target,"joomla-dropdown")||this.close())})),e.forEach((t=>{t.addEventListener("click",(()=>{this.close()}))}))})))}dispatchCustomEvent(t){const e=new CustomEvent(t);e.relatedTarget=this,this.dispatchEvent(e),this.removeEventListener(t,this)}adoptedCallback(t,e){}attributeChangedCallback(t,e,r){}close(){const t=document.querySelector(`#${this.getAttribute("aria-labelledby")}`);this.removeAttribute("expanded"),t.setAttribute("aria-expanded",!1)}findAncestor(t,e){for(;(t=t.parentElement)&&t.nodeName.toLowerCase()!==e;);return t}}customElements.define("joomla-dropdown",t); 2 | -------------------------------------------------------------------------------- /dist/js/joomla-modal.min.js: -------------------------------------------------------------------------------- 1 | const e=9,t=27;customElements.define("joomla-modal",class extends HTMLElement{constructor(){super(),this.triggerBtn="",this.focusableElements=null,this.focusableSelectors=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex^="-"])'],this.container=this.querySelector(".joomla-modal-dialog")}static get observedAttributes(){return["width","height","innerWidth","innerHeight","iframe"]}connectedCallback(){if(!this.id)throw new Error("`Joomla-modal` requires an id");if(this.title=this.getAttribute("title")||"Modal",this.setAttribute("role","dialog"),this.classList.add("fade"),this.iframe=this.getAttribute("iframe")||"",this.width=this.getAttribute("width")||"100%",this.height=this.getAttribute("height")||"600px",!this.container){const e=document.createElement("div");e.classList.add("joomla-modal-dialog"),e.setAttribute("role","document"),e.innerHTML=this.innerHTML,this.innerHTML="",this.appendChild(e),this.container=this.querySelector(".joomla-modal-dialog")}this.header=this.querySelector("header"),this.main=this.querySelector("section"),this.footer=this.querySelector("footer"),this.setAttribute("tabindex",-1);const e=`modal-title-${(new Date).getUTCMilliseconds()}`;if(this.setAttribute("aria-labelledby",e),!this.header){const t=document.createElement("h5");t.innerText=this.title,t.id=e;const i=document.createElement("button");i.setAttribute("aria-label","Close"),i.setAttribute("data-dismiss",""),i.innerHTML='';const s=document.createElement("header");s.appendChild(t),s.appendChild(i),this.container.insertAdjacentElement("afterbegin",s)}this.header=this.container.querySelector("header"),this.body=this.container.querySelector("section"),this.footer=this.container.querySelector("footer"),this.triggerBtn=document.querySelector(`[data-href="#${this.id}"]`),this.triggerBtn&&this.triggerBtn.addEventListener("click",this.open.bind(this))}disconnectedCallback(){this.triggerBtn&&this.triggerBtn.removeEventListener("click",this.open)}open(){const e=document.createElement("div");if(e.classList.add("modal-backdrop","fade"),e.classList.add("modal-backdrop","show"),document.body.appendChild(e),this.removeAttribute("aria-hidden"),this.body&&(this.iframeEl=this.main.querySelector("iframe"),this.iframe)){this.iframeEl&&this.iframeEl.parentNode.remove(this.iframeEl);const e=document.createElement("iframe");e.width=this.width,e.height=this.height,e.src=this.iframe,e.setAttribute("frameborder",0),this.body.appendChild(e),this.iframeEl=this.main.querySelector("iframe")}this.adjustDimensions(),this.scrollTop=0,this.classList.add("show"),this.focusableElements=[].slice.call(this.querySelectorAll(this.focusableSelectors.join())),this.focusableElements.length?this.focusableElements[0].focus():this.header.querySelector("button").focus(),this.evKeypress=this.keyPress.bind(this),this.evClose=this.close.bind(this),this.evDocumentClose=this.documentClose.bind(this),this.addEventListener("keydown",this.evKeypress),document.addEventListener("click",this.evDocumentClose);[].slice.call(this.querySelectorAll("[data-dismiss]")).forEach((e=>{e.addEventListener("click",this.evClose)}))}close(){this.removeEventListener("keydown",this.evKeypress),document.removeEventListener("click",this.evDocumentClose);[].slice.call(this.querySelectorAll("[data-dismiss]")).forEach((e=>{e.removeEventListener("click",this.evClose)}));const e=document.querySelector(".modal-backdrop");e&&document.body.removeChild(e),this.setAttribute("aria-hidden","true"),this.classList.remove("show"),this.main.innerHTML="",this.triggerBtn.focus()}documentClose(e){this.findAncestorByClass(e.target,"joomla-modal-dialog")||e.target===this.triggerBtn||this.close()}keyPress(i){if(i.keyCode===t&&this.close(),i.keyCode===e){const e=this.focusableElements.indexOf(document.activeElement);!i.shiftKey||0!==e&&-1!==e||(this.focusableElements[this.focusableElements.length-1].focus(),i.preventDefault()),i.shiftKey||e!==this.focusableElements.length-1||(this.focusableElements[0].focus(),i.preventDefault())}}adjustDimensions(){let e=this.offsetHeight;e+=parseInt(window.getComputedStyle(this).getPropertyValue("margin-top"),10),e+=parseInt(window.getComputedStyle(this).getPropertyValue("margin-bottom"),10);const t=this.body.getBoundingClientRect.height;let i=this.body.offsetHeight;i+=parseInt(window.getComputedStyle(this.body).getPropertyValue("margin-top"),10),i+=parseInt(window.getComputedStyle(this.body).getPropertyValue("margin-bottom"),10);let s=this.header.offsetHeight;s+=parseInt(window.getComputedStyle(this.header).getPropertyValue("margin-top"),10),s+=parseInt(window.getComputedStyle(this.header).getPropertyValue("margin-bottom"),10);let o=this.footer.offsetHeight;o+=parseInt(window.getComputedStyle(this.footer).getPropertyValue("margin-top"),10),o+=parseInt(window.getComputedStyle(this.footer).getPropertyValue("margin-bottom"),10);const r=this.offsetTop,n=window.height-2*r,a=i-t,l=n-(s+o+a);if(this.iframeEl){this.iframeEl.getBoundingClientRect().height>l&&(this.container.style.maxHeight=l,this.container.style.overflowY="auto",this.iframeEl.style.maxHeight=l-a)}else e>n&&(this.container.style.maxHeight=l,this.container.style.overflowY="auto")}findAncestorByClass(e,t){for(;(e=e.parentElement)&&!e.classList.contains(t););return e}}); 2 | -------------------------------------------------------------------------------- /dist/js/joomla-tip-es5.min.js: -------------------------------------------------------------------------------- 1 | function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){for(var r=0;r').concat(this.tip,"")}},{key:"dispatchCustomEvent",value:function(t){var e=new CustomEvent(t,{bubbles:!0,cancelable:!0});e.relatedTarget=this,this.dispatchEvent(e),this.removeEventListener(t,this)}}],c=[{key:"observedAttributes",get:function(){return["type","label","tip","text","position"]}}],o&&e(n.prototype,o),c&&e(n,c),Object.defineProperty(n,"prototype",{writable:!1}),n;var n,o,c}();customElements.define("joomla-tip",s); 2 | -------------------------------------------------------------------------------- /dist/js/joomla-tip.js: -------------------------------------------------------------------------------- 1 | class TipElement extends HTMLElement { 2 | /* Attributes to monitor */ 3 | static get observedAttributes() { return ['type', 'label', 'tip', 'text', 'position']; } 4 | 5 | get type() { return this.getAttribute('type'); } 6 | 7 | set type(value) { this.setAttribute('type', value); } 8 | 9 | get label() { return this.getAttribute('label'); } 10 | 11 | set label(value) { this.setAttribute('label', value); } 12 | 13 | get tip() { return this.getAttribute('tip'); } 14 | 15 | set tip(value) { this.setAttribute('tip', value); } 16 | 17 | get position() { return this.getAttribute('position'); } 18 | 19 | set position(value) { this.setAttribute('position', value); } 20 | 21 | get text() { return this.getAttribute('text'); } 22 | 23 | set text(value) { this.getAttribute('text', value); } 24 | 25 | /* Lifecycle, element appended to the DOM */ 26 | connectedCallback() { 27 | if (!this.position || (this.position && ['top', 'bottom', 'left', 'right'].indexOf(this.position) === -1)) { 28 | this.position = 'top'; 29 | } 30 | 31 | // create the html 32 | this.btnElement = document.createElement('button'); 33 | this.spanElement = document.createElement('span'); 34 | 35 | this.btnElement.setAttribute('aria-label', this.label ? this.label : 'more info'); 36 | this.btnElement.innerHTML = this.text ? this.text : ''; 37 | this.spanElement.setAttribute('role', 'status'); 38 | 39 | // On click 40 | this.btnElement.addEventListener('click', this.showTip.bind(this)); 41 | 42 | this.append(this.btnElement); 43 | this.append(this.spanElement); 44 | } 45 | 46 | /* Lifecycle, element removed from the DOM */ 47 | disconnectedCallback() { 48 | this.querySelector('button').removeEventListener('click', this.showTip, true); 49 | } 50 | 51 | showTip() { 52 | const self = this; 53 | 54 | // Close on outside click 55 | document.addEventListener('click', (e) => { 56 | if (this.btnElement !== e.target) { 57 | this.spanElement.innerHTML = ''; 58 | self.removeEventListener('keydown', this); 59 | } 60 | }); 61 | 62 | // Remove toggletip on ESC 63 | document.addEventListener('keydown', (e) => { 64 | if ((e.keyCode || e.which) === 9) { 65 | this.spanElement.innerHTML = ''; 66 | self.removeEventListener('keydown', this); 67 | } 68 | }); 69 | 70 | this.spanElement.innerHTML = `${this.tip}`; 71 | } 72 | 73 | /* Method to dispatch events */ 74 | dispatchCustomEvent(eventName) { 75 | const OriginalCustomEvent = new CustomEvent(eventName, { bubbles: true, cancelable: true }); 76 | OriginalCustomEvent.relatedTarget = this; 77 | this.dispatchEvent(OriginalCustomEvent); 78 | this.removeEventListener(eventName, this); 79 | } 80 | } 81 | customElements.define('joomla-tip', TipElement); 82 | -------------------------------------------------------------------------------- /dist/js/joomla-tip.min.js: -------------------------------------------------------------------------------- 1 | class t extends HTMLElement{static get observedAttributes(){return["type","label","tip","text","position"]}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get label(){return this.getAttribute("label")}set label(t){this.setAttribute("label",t)}get tip(){return this.getAttribute("tip")}set tip(t){this.setAttribute("tip",t)}get position(){return this.getAttribute("position")}set position(t){this.setAttribute("position",t)}get text(){return this.getAttribute("text")}set text(t){this.getAttribute("text",t)}connectedCallback(){(!this.position||this.position&&-1===["top","bottom","left","right"].indexOf(this.position))&&(this.position="top"),this.btnElement=document.createElement("button"),this.spanElement=document.createElement("span"),this.btnElement.setAttribute("aria-label",this.label?this.label:"more info"),this.btnElement.innerHTML=this.text?this.text:"",this.spanElement.setAttribute("role","status"),this.btnElement.addEventListener("click",this.showTip.bind(this)),this.append(this.btnElement),this.append(this.spanElement)}disconnectedCallback(){this.querySelector("button").removeEventListener("click",this.showTip,!0)}showTip(){const t=this;document.addEventListener("click",(e=>{this.btnElement!==e.target&&(this.spanElement.innerHTML="",t.removeEventListener("keydown",this))})),document.addEventListener("keydown",(e=>{9===(e.keyCode||e.which)&&(this.spanElement.innerHTML="",t.removeEventListener("keydown",this))})),this.spanElement.innerHTML=`${this.tip}`}dispatchCustomEvent(t){const e=new CustomEvent(t,{bubbles:!0,cancelable:!0});e.relatedTarget=this,this.dispatchEvent(e),this.removeEventListener(t,this)}}customElements.define("joomla-tip",t); 2 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joomla-projects/custom-elements/556d80ea4c5f30b9bddd7540ee079eef76972652/docs/.nojekyll -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ## Joomla UI Componens 2 | 3 | > A collection of framework agnostic UI components used in the Joomla CMS and released independently. 4 | 5 | ## What are Custom Elements? 6 | Custom Elements allow you to create custom HTML Tags or extend other people's HTML Tags. For more information on Custom 7 | Elements we strongy recommend you read the Google Documentation [here](https://developers.google.com/web/fundamentals/web-components/customelements). 8 | 9 | ## What is the Vision? 10 | These custom elements have been built to allow long term development of core components used on many websites. Our aim 11 | is to allow these to work with many UI frameworks that are commonly used across the internet allowing people to focus on 12 | styling in CSS - whilst we focus here on the more complicated Javascript Elements. 13 | 14 | ## What Elements are provided? 15 | Please view the components menu items to view information on each component provided here. 16 | -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | ![logo](_images/80px-Joomla_logo.png) 2 | 3 | 4 | # Joomla UI components 5 | 6 | > Next generation components. 7 | 8 | - Simple, fully functional and lightweight 9 | - Extremely small footprint, no dependencies 10 | - Fully customizable 11 | - CSS framework agnostic 12 | - [CSP](https://csp.withgoogle.com/docs/index.html) compliant 13 | 14 | 15 | [GitHub](https://github.com/joomla-projects/custom-elements/) 16 | [Get Started](/quickstart) 17 | 18 | 19 | ![color](#37654e) 20 | -------------------------------------------------------------------------------- /docs/_images/80px-Joomla_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joomla-projects/custom-elements/556d80ea4c5f30b9bddd7540ee079eef76972652/docs/_images/80px-Joomla_logo.png -------------------------------------------------------------------------------- /docs/_media/css/joomla-alert.css: -------------------------------------------------------------------------------- 1 | joomla-alert { 2 | --jui-alert-min-width: 250px; 3 | --jui-alert-padding: .5rem 1.25rem; 4 | --jui-alert-margin: 0 0 1rem 0; 5 | --jui-alert-border: 1px solid transparent; 6 | --jui-alert-border-radius: .25rem; 7 | --jui-alert-animation-duration: .5s; 8 | --jui-alert-animation-timing-function: ease-in-out; 9 | --jui-alert-button-color-dark: #000; 10 | --jui-alert-button-color-light: #fff; 11 | --jui-alert-success-color: #234423; 12 | --jui-alert-success-background-color: #d9e6d9; 13 | --jui-alert-success-border-color: #cadcca; 14 | --jui-alert-success-link-color: #122212; 15 | --jui-alert-info-color: #0c5460; 16 | --jui-alert-info-background-color: #d1ecf1; 17 | --jui-alert-info-border-color: #bee5eb; 18 | --jui-alert-info-link-color: #062c33; 19 | --jui-alert-warning-color: #7d5a29; 20 | --jui-alert-warning-background-color: #fcefdc; 21 | --jui-alert-warning-border-color: #fbe8cd; 22 | --jui-alert-warning-link-color: #573e1c; 23 | --jui-alert-danger-color: #712b29; 24 | --jui-alert-danger-background-color: #f7dddc; 25 | --jui-alert-danger-border-color: #f4cfce; 26 | --jui-alert-danger-link-color: #4c1d1b; 27 | display: block; 28 | min-width: var(--jui-alert-min-width, 250px); 29 | padding: var(--jui-alert-padding, 0.5rem 1.25rem); 30 | margin: var(--jui-alert-margin, 0 0 1rem 0); 31 | border: var(--jui-alert-border, 1px solid transparent); 32 | border-radius: var(--jui-alert-border-radius, 0.25rem); 33 | animation-duration: var(--jui-alert-animation-duration, 0.5s); 34 | animation-timing-function: var(--jui-alert-animation-timing-function, ease-in-out); 35 | } 36 | 37 | joomla-alert .joomla-alert--close { 38 | position: relative; 39 | top: -0.5rem; 40 | right: -1.25rem; 41 | float: right; 42 | padding: 0.2rem 1rem; 43 | font-size: 1.5rem; 44 | font-weight: 700; 45 | line-height: 1; 46 | color: var(--jui-alert-button-color-dark, #000); 47 | text-shadow: 0 1px 0 var(--jui-alert-button-color-light, #fff); 48 | background: transparent; 49 | border: 0; 50 | opacity: 0.5; 51 | } 52 | 53 | joomla-alert .joomla-alert--close:hover, 54 | joomla-alert .joomla-alert--close:focus { 55 | color: var(--jui-alert-button-color-dark, #000); 56 | text-decoration: none; 57 | cursor: pointer; 58 | opacity: 0.75; 59 | } 60 | 61 | joomla-alert[type=success] { 62 | color: var(--jui-alert-success-color, #234423); 63 | background-color: var(--jui-alert-success-background-color, #d9e6d9); 64 | border-color: var(--jui-alert-success-border-color, #cadcca); 65 | } 66 | 67 | joomla-alert[type=success] hr { 68 | border-top-color: var(--jui-alert-success-border-color, #cadcca); 69 | } 70 | 71 | joomla-alert[type=success] .alert-link { 72 | color: var(--jui-alert-success-link-color, #122212); 73 | } 74 | 75 | joomla-alert[type=info] { 76 | color: var(--jui-alert-info-color, #0c5460); 77 | background-color: var(--jui-alert-info-background-color, #d1ecf1); 78 | border-color: var(--jui-alert-info-border-color, #bee5eb); 79 | } 80 | 81 | joomla-alert[type=info] hr { 82 | border-top-color: var(--jui-alert-info-border-color, #bee5eb); 83 | } 84 | 85 | joomla-alert[type=info] .alert-link { 86 | color: var(--jui-alert-info-link-color, #062c33); 87 | } 88 | 89 | joomla-alert[type=warning] { 90 | color: var(--jui-alert-warning-color, #7d5a29); 91 | background-color: var(--jui-alert-warning-background-color, #fcefdc); 92 | border-color: var(--jui-alert-warning-border-color, #fbe8cd); 93 | } 94 | 95 | joomla-alert[type=warning] hr { 96 | border-top-color: var(--jui-alert-warning-border-color, #fbe8cd); 97 | } 98 | 99 | joomla-alert[type=warning] .alert-link { 100 | color: var(--jui-alert-warning-link-color, #573e1c); 101 | } 102 | 103 | joomla-alert[type=danger] { 104 | color: var(--jui-alert-danger-color, #712b29); 105 | background-color: var(--jui-alert-danger-background-color, #f7dddc); 106 | border-color: var(--jui-alert-danger-border-color, #f4cfce); 107 | } 108 | 109 | joomla-alert[type=danger] hr { 110 | border-top-color: var(--jui-alert-danger-border-color, #f4cfce); 111 | } 112 | 113 | joomla-alert[type=danger] .alert-link { 114 | color: var(--jui-alert-danger-link-color, #4c1d1b); 115 | } 116 | 117 | html[dir=rtl] joomla-alert .joomla-alert--close, 118 | html[dir=rtl] joomla-alert .joomla-alert-button--close { 119 | right: auto; 120 | left: -1.25rem; 121 | float: left; 122 | } 123 | 124 | @keyframes joomla-alert-fade-in { 125 | 0% { 126 | opacity: 0; 127 | } 128 | } 129 | @keyframes joomla-alert-fade-out { 130 | 0% { 131 | opacity: 1; 132 | } 133 | 100% { 134 | opacity: 0; 135 | } 136 | } 137 | @media (prefers-reduced-motion: reduce) { 138 | joomla-alert { 139 | animation-duration: 1ms !important; 140 | } 141 | } -------------------------------------------------------------------------------- /docs/_media/css/joomla-alert.min.css: -------------------------------------------------------------------------------- 1 | joomla-alert{--jui-alert-min-width:250px;--jui-alert-padding:.5rem 1.25rem;--jui-alert-margin:0 0 1rem 0;--jui-alert-border:1px solid transparent;--jui-alert-border-radius:.25rem;--jui-alert-animation-duration:.5s;--jui-alert-animation-timing-function:ease-in-out;--jui-alert-button-color-dark:#000;--jui-alert-button-color-light:#fff;--jui-alert-success-color:#234423;--jui-alert-success-background-color:#d9e6d9;--jui-alert-success-border-color:#cadcca;--jui-alert-success-link-color:#122212;--jui-alert-info-color:#0c5460;--jui-alert-info-background-color:#d1ecf1;--jui-alert-info-border-color:#bee5eb;--jui-alert-info-link-color:#062c33;--jui-alert-warning-color:#7d5a29;--jui-alert-warning-background-color:#fcefdc;--jui-alert-warning-border-color:#fbe8cd;--jui-alert-warning-link-color:#573e1c;--jui-alert-danger-color:#712b29;--jui-alert-danger-background-color:#f7dddc;--jui-alert-danger-border-color:#f4cfce;--jui-alert-danger-link-color:#4c1d1b;animation-duration:var(--jui-alert-animation-duration,.5s);animation-timing-function:var(--jui-alert-animation-timing-function,ease-in-out);border:var(--jui-alert-border,1px solid transparent);border-radius:var(--jui-alert-border-radius,.25rem);display:block;margin:var(--jui-alert-margin,0 0 1rem 0);min-width:var(--jui-alert-min-width,250px);padding:var(--jui-alert-padding,.5rem 1.25rem)}joomla-alert .joomla-alert--close{background:transparent;border:0;color:var(--jui-alert-button-color-dark,#000);float:right;font-size:1.5rem;font-weight:700;line-height:1;opacity:.5;padding:.2rem 1rem;position:relative;right:-1.25rem;text-shadow:0 1px 0 var(--jui-alert-button-color-light,#fff);top:-.5rem}joomla-alert .joomla-alert--close:focus,joomla-alert .joomla-alert--close:hover{color:var(--jui-alert-button-color-dark,#000);cursor:pointer;opacity:.75;text-decoration:none}joomla-alert[type=success]{background-color:var(--jui-alert-success-background-color,#d9e6d9);border-color:var(--jui-alert-success-border-color,#cadcca);color:var(--jui-alert-success-color,#234423)}joomla-alert[type=success] hr{border-top-color:var(--jui-alert-success-border-color,#cadcca)}joomla-alert[type=success] .alert-link{color:var(--jui-alert-success-link-color,#122212)}joomla-alert[type=info]{background-color:var(--jui-alert-info-background-color,#d1ecf1);border-color:var(--jui-alert-info-border-color,#bee5eb);color:var(--jui-alert-info-color,#0c5460)}joomla-alert[type=info] hr{border-top-color:var(--jui-alert-info-border-color,#bee5eb)}joomla-alert[type=info] .alert-link{color:var(--jui-alert-info-link-color,#062c33)}joomla-alert[type=warning]{background-color:var(--jui-alert-warning-background-color,#fcefdc);border-color:var(--jui-alert-warning-border-color,#fbe8cd);color:var(--jui-alert-warning-color,#7d5a29)}joomla-alert[type=warning] hr{border-top-color:var(--jui-alert-warning-border-color,#fbe8cd)}joomla-alert[type=warning] .alert-link{color:var(--jui-alert-warning-link-color,#573e1c)}joomla-alert[type=danger]{background-color:var(--jui-alert-danger-background-color,#f7dddc);border-color:var(--jui-alert-danger-border-color,#f4cfce);color:var(--jui-alert-danger-color,#712b29)}joomla-alert[type=danger] hr{border-top-color:var(--jui-alert-danger-border-color,#f4cfce)}joomla-alert[type=danger] .alert-link{color:var(--jui-alert-danger-link-color,#4c1d1b)}html[dir=rtl] joomla-alert .joomla-alert--close,html[dir=rtl] joomla-alert .joomla-alert-button--close{float:left;left:-1.25rem;right:auto}@keyframes joomla-alert-fade-in{0%{opacity:0}}@keyframes joomla-alert-fade-out{0%{opacity:1}to{opacity:0}}@media (prefers-reduced-motion:reduce){joomla-alert{animation-duration:1ms!important}} -------------------------------------------------------------------------------- /docs/_media/css/joomla-collapse.css: -------------------------------------------------------------------------------- 1 | joomla-collapse[state=closed] { 2 | display: none; 3 | } 4 | joomla-collapse[state=open] { 5 | display: block; 6 | } -------------------------------------------------------------------------------- /docs/_media/css/joomla-collapse.min.css: -------------------------------------------------------------------------------- 1 | joomla-collapse[state=closed]{display:none}joomla-collapse[state=open]{display:block} -------------------------------------------------------------------------------- /docs/_media/css/joomla-dropdown.css: -------------------------------------------------------------------------------- 1 | joomla-dropdown { 2 | position: absolute; 3 | top: 30px; 4 | left: 0; 5 | z-index: 1000; 6 | box-sizing: border-box; 7 | display: none; 8 | min-width: 10rem; 9 | margin-top: 0.5rem; 10 | font-size: 1rem; 11 | text-align: left; 12 | list-style: none; 13 | background-color: #fff; 14 | background-clip: padding-box; 15 | border: 1px solid rgba(0, 0, 0, 0.15); 16 | } 17 | joomla-dropdown[expanded] { 18 | display: block; 19 | } 20 | joomla-dropdown .dropdown-item { 21 | display: block; 22 | padding: 0.5rem 0.75rem; 23 | clear: both; 24 | font-weight: 400; 25 | color: #212529; 26 | text-align: inherit; 27 | white-space: nowrap; 28 | background-color: transparent; 29 | border: 0; 30 | } 31 | joomla-dropdown .dropdown-item:hover, joomla-dropdown .dropdown-item:focus { 32 | color: #fff; 33 | text-decoration: none; 34 | cursor: pointer; 35 | background: #495057; 36 | } 37 | 38 | .joomla-dropdown-container { 39 | position: relative; 40 | display: inline-flex; 41 | vertical-align: middle; 42 | } 43 | 44 | html[dir=rtl] joomla-dropdown { 45 | right: 0; 46 | left: auto; 47 | } -------------------------------------------------------------------------------- /docs/_media/css/joomla-dropdown.min.css: -------------------------------------------------------------------------------- 1 | joomla-dropdown{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.15);box-sizing:border-box;display:none;font-size:1rem;left:0;list-style:none;margin-top:.5rem;min-width:10rem;position:absolute;text-align:left;top:30px;z-index:1000}joomla-dropdown[expanded]{display:block}joomla-dropdown .dropdown-item{background-color:transparent;border:0;clear:both;color:#212529;display:block;font-weight:400;padding:.5rem .75rem;text-align:inherit;white-space:nowrap}joomla-dropdown .dropdown-item:focus,joomla-dropdown .dropdown-item:hover{background:#495057;color:#fff;cursor:pointer;text-decoration:none}.joomla-dropdown-container{display:inline-flex;position:relative;vertical-align:middle}html[dir=rtl] joomla-dropdown{left:auto;right:0} -------------------------------------------------------------------------------- /docs/_media/css/joomla-modal.css: -------------------------------------------------------------------------------- 1 | joomla-modal { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | bottom: 0; 6 | left: 0; 7 | z-index: 1050; 8 | box-sizing: inherit; 9 | display: none; 10 | max-width: 500px; 11 | margin: 10px auto; 12 | overflow: hidden; 13 | border-radius: 5px; 14 | outline: 0; 15 | } 16 | joomla-modal.jviewport-width10 { 17 | width: 10vw; 18 | margin-left: -5vw; 19 | } 20 | joomla-modal.jviewport-width20 { 21 | width: 20vw; 22 | margin-left: -10vw; 23 | } 24 | joomla-modal.jviewport-width30 { 25 | width: 30vw; 26 | margin-left: -15vw; 27 | } 28 | joomla-modal.jviewport-width40 { 29 | width: 40vw; 30 | margin-left: -20vw; 31 | } 32 | joomla-modal.jviewport-width50 { 33 | width: 50vw; 34 | margin-left: -25vw; 35 | } 36 | joomla-modal.jviewport-width60 { 37 | width: 60vw; 38 | margin-left: -30vw; 39 | } 40 | joomla-modal.jviewport-width70 { 41 | width: 70vw; 42 | margin-left: -35vw; 43 | } 44 | joomla-modal.jviewport-width80 { 45 | width: 80vw; 46 | margin-left: -40vw; 47 | } 48 | joomla-modal.jviewport-width90 { 49 | width: 90vw; 50 | margin-left: -45vw; 51 | } 52 | joomla-modal.jviewport-width100 { 53 | width: 100vw; 54 | margin-left: -50vw; 55 | } 56 | joomla-modal.show { 57 | display: block; 58 | } 59 | joomla-modal .joomla-modal-dialog { 60 | position: relative; 61 | display: flex; 62 | flex-direction: column; 63 | background-color: #fff; 64 | background-clip: padding-box; 65 | border: 1px solid rgba(0, 0, 0, 0.2); 66 | border-radius: 0.3rem; 67 | outline: 0; 68 | } 69 | joomla-modal .joomla-modal-dialog.fade { 70 | opacity: 0; 71 | transition: opacity 0.15s linear; 72 | } 73 | joomla-modal .joomla-modal-dialog.fade.show { 74 | opacity: 1; 75 | } 76 | joomla-modal .joomla-modal-dialog header { 77 | display: flex; 78 | align-items: center; 79 | justify-content: space-between; 80 | padding: 15px; 81 | border-bottom: 1px solid #e9ecef; 82 | } 83 | joomla-modal .joomla-modal-dialog header button { 84 | float: right; 85 | padding: 0; 86 | font-size: 1.5rem; 87 | font-weight: 700; 88 | line-height: 1; 89 | color: #000; 90 | text-shadow: 0 1px 0 #fff; 91 | cursor: pointer; 92 | background: 0 0; 93 | border: 0; 94 | opacity: 0.5; 95 | -webkit-appearance: none; 96 | -moz-appearance: none; 97 | appearance: none; 98 | } 99 | joomla-modal .joomla-modal-dialog header h5 { 100 | margin-bottom: 0; 101 | font-size: 1.25rem; 102 | line-height: 1.5; 103 | } 104 | joomla-modal .joomla-modal-dialog section { 105 | position: relative; 106 | flex: 1 1 auto; 107 | padding: 15px; 108 | } 109 | joomla-modal .joomla-modal-dialog section.jviewport-height10 { 110 | height: 10vh; 111 | } 112 | joomla-modal .joomla-modal-dialog section.jviewport-height20 { 113 | height: 20vh; 114 | } 115 | joomla-modal .joomla-modal-dialog section.jviewport-height30 { 116 | height: 30vh; 117 | } 118 | joomla-modal .joomla-modal-dialog section.jviewport-height40 { 119 | height: 40vh; 120 | } 121 | joomla-modal .joomla-modal-dialog section.jviewport-height50 { 122 | height: 50vh; 123 | } 124 | joomla-modal .joomla-modal-dialog section.jviewport-height60 { 125 | height: 60vh; 126 | } 127 | joomla-modal .joomla-modal-dialog section.jviewport-height70 { 128 | height: 70vh; 129 | } 130 | joomla-modal .joomla-modal-dialog section.jviewport-height80 { 131 | height: 80vh; 132 | } 133 | joomla-modal .joomla-modal-dialog section.jviewport-height90 { 134 | height: 90vh; 135 | } 136 | joomla-modal .joomla-modal-dialog section.jviewport-height100 { 137 | height: 100vh; 138 | } 139 | joomla-modal .joomla-modal-dialog section[class^=jviewport-height], 140 | joomla-modal .joomla-modal-dialog section[class*=jviewport-height] { 141 | max-height: none; 142 | } 143 | joomla-modal .joomla-modal-dialog footer { 144 | display: flex; 145 | align-items: center; 146 | justify-content: flex-end; 147 | padding: 15px; 148 | border-top: 1px solid #e9ecef; 149 | } 150 | joomla-modal .joomla-modal-dialog footer .btn { 151 | margin-left: 10px; 152 | } 153 | 154 | .modal-backdrop.show { 155 | opacity: 0.5; 156 | } 157 | 158 | .modal-backdrop { 159 | position: fixed; 160 | top: 0; 161 | right: 0; 162 | bottom: 0; 163 | left: 0; 164 | z-index: 1040; 165 | background-color: #000; 166 | } -------------------------------------------------------------------------------- /docs/_media/css/joomla-modal.min.css: -------------------------------------------------------------------------------- 1 | joomla-modal{border-radius:5px;bottom:0;box-sizing:inherit;display:none;left:0;margin:10px auto;max-width:500px;outline:0;overflow:hidden;position:fixed;right:0;top:0;z-index:1050}joomla-modal.jviewport-width10{margin-left:-5vw;width:10vw}joomla-modal.jviewport-width20{margin-left:-10vw;width:20vw}joomla-modal.jviewport-width30{margin-left:-15vw;width:30vw}joomla-modal.jviewport-width40{margin-left:-20vw;width:40vw}joomla-modal.jviewport-width50{margin-left:-25vw;width:50vw}joomla-modal.jviewport-width60{margin-left:-30vw;width:60vw}joomla-modal.jviewport-width70{margin-left:-35vw;width:70vw}joomla-modal.jviewport-width80{margin-left:-40vw;width:80vw}joomla-modal.jviewport-width90{margin-left:-45vw;width:90vw}joomla-modal.jviewport-width100{margin-left:-50vw;width:100vw}joomla-modal.show{display:block}joomla-modal .joomla-modal-dialog{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;display:flex;flex-direction:column;outline:0;position:relative}joomla-modal .joomla-modal-dialog.fade{opacity:0;transition:opacity .15s linear}joomla-modal .joomla-modal-dialog.fade.show{opacity:1}joomla-modal .joomla-modal-dialog header{align-items:center;border-bottom:1px solid #e9ecef;display:flex;justify-content:space-between;padding:15px}joomla-modal .joomla-modal-dialog header button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:0 0;border:0;color:#000;cursor:pointer;float:right;font-size:1.5rem;font-weight:700;line-height:1;opacity:.5;padding:0;text-shadow:0 1px 0 #fff}joomla-modal .joomla-modal-dialog header h5{font-size:1.25rem;line-height:1.5;margin-bottom:0}joomla-modal .joomla-modal-dialog section{flex:1 1 auto;padding:15px;position:relative}joomla-modal .joomla-modal-dialog section.jviewport-height10{height:10vh}joomla-modal .joomla-modal-dialog section.jviewport-height20{height:20vh}joomla-modal .joomla-modal-dialog section.jviewport-height30{height:30vh}joomla-modal .joomla-modal-dialog section.jviewport-height40{height:40vh}joomla-modal .joomla-modal-dialog section.jviewport-height50{height:50vh}joomla-modal .joomla-modal-dialog section.jviewport-height60{height:60vh}joomla-modal .joomla-modal-dialog section.jviewport-height70{height:70vh}joomla-modal .joomla-modal-dialog section.jviewport-height80{height:80vh}joomla-modal .joomla-modal-dialog section.jviewport-height90{height:90vh}joomla-modal .joomla-modal-dialog section.jviewport-height100{height:100vh}joomla-modal .joomla-modal-dialog section[class*=jviewport-height],joomla-modal .joomla-modal-dialog section[class^=jviewport-height]{max-height:none}joomla-modal .joomla-modal-dialog footer{align-items:center;border-top:1px solid #e9ecef;display:flex;justify-content:flex-end;padding:15px}joomla-modal .joomla-modal-dialog footer .btn{margin-left:10px}.modal-backdrop.show{opacity:.5}.modal-backdrop{background-color:#000;bottom:0;left:0;position:fixed;right:0;top:0;z-index:1040} -------------------------------------------------------------------------------- /docs/_media/css/joomla-panels.css: -------------------------------------------------------------------------------- 1 | joomla-panels { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | joomla-panels > ul { 6 | display: flex; 7 | padding: 0; 8 | margin: 0; 9 | overflow-x: auto; 10 | overflow-y: hidden; 11 | white-space: nowrap; 12 | list-style: outside none none; 13 | background-color: #3073bb; 14 | } 15 | joomla-panels > ul[role=tablist] { 16 | padding: 0; 17 | margin: 0; 18 | } 19 | joomla-panels a[role=tab] { 20 | position: relative; 21 | display: block; 22 | padding: 0.75rem 1rem 0.85rem; 23 | color: #fff; 24 | text-decoration: none; 25 | } 26 | joomla-panels a[role=tab][active] { 27 | background-color: rgba(0, 0, 0, 0.2); 28 | } 29 | joomla-panels a[role=tab][active]::after { 30 | position: absolute; 31 | right: 0; 32 | bottom: -1px; 33 | left: 0; 34 | height: 5px; 35 | content: ""; 36 | background-color: rgba(0, 0, 0, 0.2); 37 | opacity: 0.8; 38 | } 39 | joomla-panels > section { 40 | display: none; 41 | padding: 15px 0; 42 | background-color: #fefefe; 43 | } 44 | joomla-panels > section[active] { 45 | display: block; 46 | } 47 | joomla-panels[orientation=vertical] { 48 | flex-direction: row; 49 | align-items: flex-start; 50 | } 51 | joomla-panels[orientation=vertical] > ul { 52 | flex-direction: column; 53 | min-width: 30%; 54 | height: auto; 55 | overflow: hidden; 56 | } 57 | joomla-panels[orientation=vertical] li:last-of-type a { 58 | border-bottom: 0; 59 | } 60 | joomla-panels[orientation=vertical] a { 61 | position: relative; 62 | display: block; 63 | padding: 0.75rem 1rem 0.85rem; 64 | color: #fff; 65 | text-decoration: none; 66 | } 67 | joomla-panels[orientation=vertical] a[active] { 68 | background-color: #fff; 69 | background-image: none; 70 | border-right: 0 none; 71 | border-left: 0 none; 72 | box-shadow: none; 73 | } 74 | joomla-panels[orientation=vertical] a[active]::after { 75 | top: 0; 76 | bottom: 0; 77 | left: -1px; 78 | width: 5px; 79 | height: auto; 80 | } 81 | joomla-panels[orientation=vertical] > section { 82 | padding: 15px 0; 83 | border: 0 none; 84 | box-shadow: none; 85 | } 86 | joomla-panels[view=accordion] > ul { 87 | flex-direction: column; 88 | white-space: normal; 89 | } 90 | joomla-panels[view=accordion] section { 91 | display: none; 92 | padding: 15px 0; 93 | } 94 | joomla-panels[view=accordion] section[active] { 95 | display: block; 96 | } 97 | joomla-panels[view=accordion] [active] { 98 | background-color: #fff; 99 | } 100 | joomla-panels[view=accordion] a[role=tab][active]::after { 101 | top: 0; 102 | left: 0; 103 | width: 5px; 104 | height: 100%; 105 | } 106 | 107 | joomla-panels[type=primary] a[role=tab][active]::after { 108 | background-color: #006898; 109 | } 110 | 111 | joomla-panels[type=secondary] a[role=tab][active]::after { 112 | background-color: #6c757d; 113 | } 114 | 115 | joomla-panels[type=success] a[role=tab][active]::after { 116 | background-color: #438243; 117 | } 118 | 119 | joomla-panels[type=info] a[role=tab][active]::after { 120 | background-color: #17a2b8; 121 | } 122 | 123 | joomla-panels[type=warning] a[role=tab][active]::after { 124 | background-color: #f0ad4e; 125 | } 126 | 127 | joomla-panels[type=danger] a[role=tab][active]::after { 128 | background-color: #d9534f; 129 | } 130 | 131 | joomla-panels[type=light] a[role=tab][active]::after { 132 | background-color: #f8f9fa; 133 | } 134 | 135 | joomla-panels[type=dark] a[role=tab][active]::after { 136 | background-color: #343a40; 137 | } -------------------------------------------------------------------------------- /docs/_media/css/joomla-panels.min.css: -------------------------------------------------------------------------------- 1 | joomla-panels{display:flex;flex-direction:column}joomla-panels>ul{background-color:#3073bb;display:flex;list-style:none outside none;overflow-x:auto;overflow-y:hidden;white-space:nowrap}joomla-panels>ul,joomla-panels>ul[role=tablist]{margin:0;padding:0}joomla-panels a[role=tab]{color:#fff;display:block;padding:.75rem 1rem .85rem;position:relative;text-decoration:none}joomla-panels a[role=tab][active]{background-color:rgba(0,0,0,.2)}joomla-panels a[role=tab][active]:after{background-color:rgba(0,0,0,.2);bottom:-1px;content:"";height:5px;left:0;opacity:.8;position:absolute;right:0}joomla-panels>section{background-color:#fefefe;display:none;padding:15px 0}joomla-panels>section[active]{display:block}joomla-panels[orientation=vertical]{align-items:flex-start;flex-direction:row}joomla-panels[orientation=vertical]>ul{flex-direction:column;height:auto;min-width:30%;overflow:hidden}joomla-panels[orientation=vertical] li:last-of-type a{border-bottom:0}joomla-panels[orientation=vertical] a{color:#fff;display:block;padding:.75rem 1rem .85rem;position:relative;text-decoration:none}joomla-panels[orientation=vertical] a[active]{background-color:#fff;background-image:none;border-left:0;border-right:0;box-shadow:none}joomla-panels[orientation=vertical] a[active]:after{bottom:0;height:auto;left:-1px;top:0;width:5px}joomla-panels[orientation=vertical]>section{border:0;box-shadow:none;padding:15px 0}joomla-panels[view=accordion]>ul{flex-direction:column;white-space:normal}joomla-panels[view=accordion] section{display:none;padding:15px 0}joomla-panels[view=accordion] section[active]{display:block}joomla-panels[view=accordion] [active]{background-color:#fff}joomla-panels[view=accordion] a[role=tab][active]:after{height:100%;left:0;top:0;width:5px}joomla-panels[type=primary] a[role=tab][active]:after{background-color:#006898}joomla-panels[type=secondary] a[role=tab][active]:after{background-color:#6c757d}joomla-panels[type=success] a[role=tab][active]:after{background-color:#438243}joomla-panels[type=info] a[role=tab][active]:after{background-color:#17a2b8}joomla-panels[type=warning] a[role=tab][active]:after{background-color:#f0ad4e}joomla-panels[type=danger] a[role=tab][active]:after{background-color:#d9534f}joomla-panels[type=light] a[role=tab][active]:after{background-color:#f8f9fa}joomla-panels[type=dark] a[role=tab][active]:after{background-color:#343a40} -------------------------------------------------------------------------------- /docs/_media/css/joomla-tab.css: -------------------------------------------------------------------------------- 1 | joomla-tab { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | joomla-tab[view=tabs] > div[role=tablist] { 7 | display: flex; 8 | padding: 0; 9 | margin: 0; 10 | overflow-x: auto; 11 | overflow-y: hidden; 12 | white-space: nowrap; 13 | list-style: outside none none; 14 | background-color: #f5f5f5; 15 | border-color: #ccc #ccc currentcolor; 16 | border-style: solid solid none; 17 | border-width: 1px 1px 0; 18 | border-radius: 0.25rem 0.25rem 0 0; 19 | -o-border-image: none; 20 | border-image: none; 21 | box-shadow: 0 1px #fff inset, 0 2px 3px -3px rgba(0, 0, 0, 0.15), 0 -4px 0 rgba(0, 0, 0, 0.05) inset, 0 0 3px rgba(0, 0, 0, 0.04); 22 | } 23 | 24 | joomla-tab[view=accordion] > div[role=tablist] { 25 | display: none; 26 | } 27 | 28 | joomla-tab button[role=tab] { 29 | position: relative; 30 | display: block; 31 | padding: 0.75em 1em; 32 | color: #0d1321; 33 | text-decoration: none; 34 | background-color: transparent; 35 | border: unset; 36 | box-shadow: 1px 0 0 rgba(0, 0, 0, 0.05); 37 | -webkit-appearance: none; 38 | -moz-appearance: none; 39 | appearance: none; 40 | } 41 | 42 | joomla-tab button[role=tab][aria-expanded=true], 43 | joomla-tab button[role=tab][aria-selected=true] { 44 | background-color: rgba(0, 0, 0, 0.03); 45 | background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.05) 100%); 46 | border-right: 0 none; 47 | border-left: 0 none; 48 | border-top-left-radius: 0; 49 | border-top-right-radius: 0; 50 | box-shadow: 2px 0 1px -1px rgba(0, 0, 0, 0.08) inset, -2px 0 1px -1px rgba(0, 0, 0, 0.08) inset, 0 1px 0 rgba(0, 0, 0, 0.02) inset; 51 | } 52 | 53 | joomla-tab button[aria-expanded=true]::after, 54 | joomla-tab button[aria-selected=true]::after { 55 | position: absolute; 56 | right: 0; 57 | bottom: -1px; 58 | left: 0; 59 | height: 5px; 60 | content: ""; 61 | background-color: #006898; 62 | opacity: 0.8; 63 | } 64 | 65 | joomla-tab > joomla-tab-element { 66 | position: relative; 67 | display: none; 68 | padding: 15px; 69 | background-color: #fefefe; 70 | border: 1px solid #ccc; 71 | border-radius: 0 0 0.25rem 0.25rem; 72 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.04); 73 | } 74 | 75 | joomla-tab > joomla-tab-element[active] { 76 | display: block; 77 | } 78 | 79 | joomla-tab[orientation=vertical] { 80 | flex-direction: row; 81 | align-items: flex-start; 82 | } 83 | 84 | joomla-tab[orientation=vertical] > div[role=tablist] { 85 | flex-direction: column; 86 | min-width: 30%; 87 | height: auto; 88 | overflow: hidden; 89 | border: 1px solid #ccc; 90 | border-radius: 0.25rem; 91 | box-shadow: none; 92 | } 93 | 94 | joomla-tab[orientation=vertical] > div[role=tablist] button:last-of-type { 95 | border-bottom: 0; 96 | } 97 | 98 | joomla-tab[orientation=vertical] > div[role=tablist] button { 99 | position: relative; 100 | display: block; 101 | padding: 0.75em 1em; 102 | color: #0d1321; 103 | text-decoration: none; 104 | background-color: transparent; 105 | border-bottom: 1px solid #ddd; 106 | box-shadow: none; 107 | -webkit-appearance: none; 108 | -moz-appearance: none; 109 | appearance: none; 110 | } 111 | 112 | joomla-tab[orientation=vertical] > div[role=tablist] button[aria-expanded=true] { 113 | background-color: #fff; 114 | background-image: none; 115 | border-right: 0 none; 116 | border-left: 0 none; 117 | box-shadow: none; 118 | } 119 | 120 | joomla-tab[orientation=vertical] > div[role=tablist] button[aria-expanded=true]::after { 121 | top: 0; 122 | bottom: 0; 123 | left: -1px; 124 | width: 5px; 125 | height: auto; 126 | } 127 | 128 | joomla-tab[orientation=vertical] > joomla-tab-element { 129 | padding: 15px; 130 | border: 0 none; 131 | box-shadow: none; 132 | } 133 | 134 | joomla-tab[view=accordion] { 135 | flex-direction: column; 136 | white-space: normal; 137 | border-radius: 0.25rem; 138 | box-shadow: 0 1px #fff inset, 0 0 3px rgba(0, 0, 0, 0.04); 139 | } 140 | joomla-tab[view=accordion] > button { 141 | position: relative; 142 | display: block; 143 | padding: 0.75em 1em; 144 | color: #0d1321; 145 | text-decoration: none; 146 | background-color: #f5f5f5; 147 | border: unset; 148 | box-shadow: 1px 0 0 rgba(0, 0, 0, 0.05); 149 | -webkit-appearance: none; 150 | -moz-appearance: none; 151 | appearance: none; 152 | } 153 | joomla-tab[view=accordion] > button[aria-expanded=true], joomla-tab[view=accordion] > button:focus { 154 | background-color: rgba(0, 0, 0, 0.03); 155 | background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.05) 100%); 156 | } 157 | 158 | joomla-tab[view=accordion] joomla-tab-element { 159 | display: none; 160 | padding: 15px; 161 | } 162 | 163 | joomla-tab[view=accordion] joomla-tab-element[active] { 164 | display: block; 165 | border-bottom: 1px solid #ddd; 166 | } 167 | 168 | joomla-tab[view=accordion] [active] { 169 | background-color: #fff; 170 | } 171 | 172 | joomla-tab[view=accordion] button { 173 | -webkit-appearance: none; 174 | -moz-appearance: none; 175 | appearance: none; 176 | border-bottom: 1px solid #ddd; 177 | } 178 | 179 | joomla-tab[view=accordion] button[aria-expanded=true]::after { 180 | top: 0; 181 | left: 0; 182 | width: 5px; 183 | height: 100%; 184 | } -------------------------------------------------------------------------------- /docs/_media/css/joomla-tab.min.css: -------------------------------------------------------------------------------- 1 | joomla-tab{display:flex;flex-direction:column}joomla-tab[view=tabs]>div[role=tablist]{background-color:#f5f5f5;border:1px solid #ccc;border-bottom:0;-o-border-image:none;border-image:none;border-radius:.25rem .25rem 0 0;box-shadow:inset 0 1px #fff,0 2px 3px -3px rgba(0,0,0,.15),inset 0 -4px 0 rgba(0,0,0,.05),0 0 3px rgba(0,0,0,.04);display:flex;list-style:none outside none;margin:0;overflow-x:auto;overflow-y:hidden;padding:0;white-space:nowrap}joomla-tab[view=accordion]>div[role=tablist]{display:none}joomla-tab button[role=tab]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:unset;box-shadow:1px 0 0 rgba(0,0,0,.05);color:#0d1321;display:block;padding:.75em 1em;position:relative;text-decoration:none}joomla-tab button[role=tab][aria-expanded=true],joomla-tab button[role=tab][aria-selected=true]{background-color:rgba(0,0,0,.03);background-image:linear-gradient(180deg,transparent,rgba(0,0,0,.05));border-left:0;border-right:0;border-top-left-radius:0;border-top-right-radius:0;box-shadow:inset 2px 0 1px -1px rgba(0,0,0,.08),inset -2px 0 1px -1px rgba(0,0,0,.08),inset 0 1px 0 rgba(0,0,0,.02)}joomla-tab button[aria-expanded=true]:after,joomla-tab button[aria-selected=true]:after{background-color:#006898;bottom:-1px;content:"";height:5px;left:0;opacity:.8;position:absolute;right:0}joomla-tab>joomla-tab-element{background-color:#fefefe;border:1px solid #ccc;border-radius:0 0 .25rem .25rem;box-shadow:0 0 3px rgba(0,0,0,.04);display:none;padding:15px;position:relative}joomla-tab>joomla-tab-element[active]{display:block}joomla-tab[orientation=vertical]{align-items:flex-start;flex-direction:row}joomla-tab[orientation=vertical]>div[role=tablist]{border:1px solid #ccc;border-radius:.25rem;box-shadow:none;flex-direction:column;height:auto;min-width:30%;overflow:hidden}joomla-tab[orientation=vertical]>div[role=tablist] button:last-of-type{border-bottom:0}joomla-tab[orientation=vertical]>div[role=tablist] button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border-bottom:1px solid #ddd;box-shadow:none;color:#0d1321;display:block;padding:.75em 1em;position:relative;text-decoration:none}joomla-tab[orientation=vertical]>div[role=tablist] button[aria-expanded=true]{background-color:#fff;background-image:none;border-left:0;border-right:0;box-shadow:none}joomla-tab[orientation=vertical]>div[role=tablist] button[aria-expanded=true]:after{bottom:0;height:auto;left:-1px;top:0;width:5px}joomla-tab[orientation=vertical]>joomla-tab-element{border:0;box-shadow:none;padding:15px}joomla-tab[view=accordion]{border-radius:.25rem;box-shadow:inset 0 1px #fff,0 0 3px rgba(0,0,0,.04);flex-direction:column;white-space:normal}joomla-tab[view=accordion]>button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#f5f5f5;border:unset;box-shadow:1px 0 0 rgba(0,0,0,.05);color:#0d1321;display:block;padding:.75em 1em;position:relative;text-decoration:none}joomla-tab[view=accordion]>button:focus,joomla-tab[view=accordion]>button[aria-expanded=true]{background-color:rgba(0,0,0,.03);background-image:linear-gradient(180deg,transparent,rgba(0,0,0,.05))}joomla-tab[view=accordion] joomla-tab-element{display:none;padding:15px}joomla-tab[view=accordion] joomla-tab-element[active]{border-bottom:1px solid #ddd;display:block}joomla-tab[view=accordion] [active]{background-color:#fff}joomla-tab[view=accordion] button{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-bottom:1px solid #ddd}joomla-tab[view=accordion] button[aria-expanded=true]:after{height:100%;left:0;top:0;width:5px} -------------------------------------------------------------------------------- /docs/_media/css/joomla-tip.css: -------------------------------------------------------------------------------- 1 | joomla-tip { 2 | position: relative; 3 | display: inline-block; 4 | } 5 | joomla-tip button { 6 | width: 1.6rem; 7 | height: 1.6rem; 8 | font-family: serif; 9 | font-size: 1.4rem; 10 | font-weight: bold; 11 | line-height: 1.4rem; 12 | color: #fff; 13 | background: #1c3d5c; 14 | border: 0; 15 | border-radius: 50%; 16 | } 17 | joomla-tip .toggletip-bubble { 18 | position: absolute; 19 | z-index: 1040; 20 | display: inline-block; 21 | width: 14rem; 22 | padding: 0.5rem 0.8rem; 23 | font-size: 0.9rem; 24 | line-height: 1.2rem; 25 | color: #fff; 26 | background: #222; 27 | border-radius: 0.25rem; 28 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); 29 | transition: all ease-in; 30 | animation-duration: 0.3s; 31 | } 32 | joomla-tip .toggletip-bubble::after { 33 | position: absolute; 34 | top: 0.6rem; 35 | right: 100%; 36 | width: 0; 37 | height: 0; 38 | content: ""; 39 | border-style: solid; 40 | } 41 | joomla-tip .toggletip-bubble.top { 42 | bottom: 100%; 43 | left: 50%; 44 | margin-bottom: 0.6rem; 45 | transform: translate(-50%, 0); 46 | animation-name: toggletip-fadeInTop; 47 | } 48 | joomla-tip .toggletip-bubble.top::after { 49 | top: 100%; 50 | bottom: auto; 51 | left: 50%; 52 | border-color: #222 transparent transparent; 53 | border-width: 6px 6px 0; 54 | transform: translateX(-50%); 55 | } 56 | joomla-tip .toggletip-bubble.left { 57 | top: 50%; 58 | right: 100%; 59 | margin-right: 0.6rem; 60 | transform: translate(0, -50%); 61 | animation-name: toggletip-fadeInLeft; 62 | } 63 | joomla-tip .toggletip-bubble.left::after { 64 | top: 50%; 65 | bottom: auto; 66 | left: 100%; 67 | border-color: transparent transparent transparent #222; 68 | border-width: 6px 0 6px 6px; 69 | transform: translateY(-50%); 70 | } 71 | joomla-tip .toggletip-bubble.right { 72 | top: 50%; 73 | left: 100%; 74 | margin-left: 0.6rem; 75 | transform: translate(0, -50%); 76 | animation-name: toggletip-fadeInRight; 77 | } 78 | joomla-tip .toggletip-bubble.right::after { 79 | top: 50%; 80 | right: 100%; 81 | bottom: auto; 82 | border-color: transparent #222 transparent transparent; 83 | border-width: 6px 6px 6px 0; 84 | transform: translateY(-50%); 85 | } 86 | joomla-tip .toggletip-bubble.bottom { 87 | top: 100%; 88 | left: 50%; 89 | margin-top: 0.6rem; 90 | transform: translate(-50%, 0); 91 | animation-name: toggletip-fadeInBottom; 92 | } 93 | joomla-tip .toggletip-bubble.bottom::after { 94 | top: -6px; 95 | left: 50%; 96 | border-color: transparent transparent #222; 97 | border-width: 0 6px 6px; 98 | transform: translateX(-50%); 99 | } 100 | 101 | @keyframes toggletip-fadeInRight { 102 | from { 103 | opacity: 0; 104 | transform: translate(-10px, -50%); 105 | } 106 | to { 107 | opacity: 1; 108 | transform: translate(0, -50%); 109 | } 110 | } 111 | @keyframes toggletip-fadeInLeft { 112 | from { 113 | opacity: 0; 114 | transform: translate(10px, -50%); 115 | } 116 | to { 117 | opacity: 1; 118 | transform: translate(0, -50%); 119 | } 120 | } 121 | @keyframes toggletip-fadeInTop { 122 | from { 123 | opacity: 0; 124 | transform: translate(-50%, 10px); 125 | } 126 | to { 127 | opacity: 1; 128 | transform: translate(-50%, 0); 129 | } 130 | } 131 | @keyframes toggletip-fadeInBottom { 132 | from { 133 | opacity: 0; 134 | transform: translate(-50%, -10px); 135 | } 136 | to { 137 | opacity: 1; 138 | transform: translate(-50%, 0); 139 | } 140 | } -------------------------------------------------------------------------------- /docs/_media/css/joomla-tip.min.css: -------------------------------------------------------------------------------- 1 | joomla-tip{display:inline-block;position:relative}joomla-tip button{background:#1c3d5c;border:0;border-radius:50%;color:#fff;font-family:serif;font-size:1.4rem;font-weight:700;height:1.6rem;line-height:1.4rem;width:1.6rem}joomla-tip .toggletip-bubble{animation-duration:.3s;background:#222;border-radius:.25rem;box-shadow:0 0 5px rgba(0,0,0,.4);color:#fff;display:inline-block;font-size:.9rem;line-height:1.2rem;padding:.5rem .8rem;position:absolute;transition:all ease-in;width:14rem;z-index:1040}joomla-tip .toggletip-bubble:after{border-style:solid;content:"";height:0;position:absolute;right:100%;top:.6rem;width:0}joomla-tip .toggletip-bubble.top{animation-name:toggletip-fadeInTop;bottom:100%;left:50%;margin-bottom:.6rem;transform:translate(-50%)}joomla-tip .toggletip-bubble.top:after{border-color:#222 transparent transparent;border-width:6px 6px 0;bottom:auto;left:50%;top:100%;transform:translateX(-50%)}joomla-tip .toggletip-bubble.left{animation-name:toggletip-fadeInLeft;margin-right:.6rem;right:100%;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.left:after{border-color:transparent transparent transparent #222;border-width:6px 0 6px 6px;bottom:auto;left:100%;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.right{animation-name:toggletip-fadeInRight;left:100%;margin-left:.6rem;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.right:after{border-color:transparent #222 transparent transparent;border-width:6px 6px 6px 0;bottom:auto;right:100%;top:50%;transform:translateY(-50%)}joomla-tip .toggletip-bubble.bottom{animation-name:toggletip-fadeInBottom;left:50%;margin-top:.6rem;top:100%;transform:translate(-50%)}joomla-tip .toggletip-bubble.bottom:after{border-color:transparent transparent #222;border-width:0 6px 6px;left:50%;top:-6px;transform:translateX(-50%)}@keyframes toggletip-fadeInRight{0%{opacity:0;transform:translate(-10px,-50%)}to{opacity:1;transform:translateY(-50%)}}@keyframes toggletip-fadeInLeft{0%{opacity:0;transform:translate(10px,-50%)}to{opacity:1;transform:translateY(-50%)}}@keyframes toggletip-fadeInTop{0%{opacity:0;transform:translate(-50%,10px)}to{opacity:1;transform:translate(-50%)}}@keyframes toggletip-fadeInBottom{0%{opacity:0;transform:translate(-50%,-10px)}to{opacity:1;transform:translate(-50%)}} -------------------------------------------------------------------------------- /docs/_media/docs-overrides.css: -------------------------------------------------------------------------------- 1 | /** Ensure joomla tab element doesn't get any padding from the docs stylesheet */ 2 | .markdown-section joomla-tab ul { 3 | padding-left: 0; 4 | } 5 | -------------------------------------------------------------------------------- /docs/_media/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joomla-projects/custom-elements/556d80ea4c5f30b9bddd7540ee079eef76972652/docs/_media/favicon.ico -------------------------------------------------------------------------------- /docs/_media/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-alert.min.js: -------------------------------------------------------------------------------- 1 | class t extends HTMLElement{constructor(){super(),this.close=this.close.bind(this),this.destroyCloseButton=this.destroyCloseButton.bind(this),this.createCloseButton=this.createCloseButton.bind(this),this.onMutation=this.onMutation.bind(this),this.observer=new MutationObserver(this.onMutation),this.observer.observe(this,{attributes:!1,childList:!0,subtree:!0}),this.addEventListener("animationend",(t=>{"joomla-alert-fade-in"===t.animationName&&t.target===this&&(this.dispatchEvent(new CustomEvent("joomla.alert.shown")),this.style.removeProperty("animationName"))})),this.addEventListener("animationend",(t=>{"joomla-alert-fade-out"===t.animationName&&t.target===this&&(this.dispatchEvent(new CustomEvent("joomla.alert.closed")),this.remove())}))}static get observedAttributes(){return["type","role","dismiss","auto-dismiss","close-text"]}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get role(){return this.getAttribute("role")}set role(t){this.setAttribute("role",t)}get closeText(){return this.getAttribute("close-text")}set closeText(t){this.setAttribute("close-text",t)}get dismiss(){return this.getAttribute("dismiss")}set dismiss(t){this.setAttribute("dismiss",t)}get autodismiss(){return this.getAttribute("auto-dismiss")}set autodismiss(t){this.setAttribute("auto-dismiss",t)}connectedCallback(){this.dispatchEvent(new CustomEvent("joomla.alert.show")),this.style.animationName="joomla-alert-fade-in",this.type&&["info","warning","danger","success"].includes(this.type)||this.setAttribute("type","info"),this.role&&["alert","alertdialog"].includes(this.role)||this.setAttribute("role","alert"),this.firstElementChild&&"BUTTON"===this.firstElementChild.tagName&&(this.button=this.firstElementChild,this.button.classList.contains("joomla-alert--close")&&this.button.classList.add("joomla-alert--close"),""===this.button.innerHTML&&(this.button.innerHTML=''),this.button.hasAttribute("aria-label")||this.button.setAttribute("aria-label",this.closeText)),this.hasAttribute("dismiss")&&!this.button&&this.createCloseButton(),this.hasAttribute("auto-dismiss")&&this.autoDismiss()}disconnectedCallback(){this.button&&this.button.removeEventListener("click",this.close),this.observer.disconnect()}attributeChangedCallback(t,e,s){switch(t){case"type":(!s||s&&-1===["info","warning","danger","success"].indexOf(s))&&(this.type="info");break;case"role":(!s||s&&-1===["alert","alertdialog"].indexOf(s))&&(this.role="alert");break;case"dismiss":s&&""!==s||e&&""!==e?this.button&&"false"===s?this.destroyCloseButton():this.button||"false"===s||this.createCloseButton():this.button&&!this.hasAttribute("dismiss")?this.destroyCloseButton():!this.button&&this.hasAttribute("dismiss")&&this.createCloseButton();break;case"close-text":s&&s===e||this.button&&this.button.setAttribute("aria-label",s);break;case"auto-dismiss":this.autoDismiss()}}onMutation(t){for(const e of t)"childList"===e.type&&e.addedNodes.length&&this.button&&this.firstElementChild!==this.button&&this.prepend(this.button)}close(){this.dispatchEvent(new CustomEvent("joomla.alert.close")),this.style.animationName="joomla-alert-fade-out"}createCloseButton(){this.button=document.createElement("button"),this.button.setAttribute("type","button"),this.button.classList.add("joomla-alert--close"),this.button.innerHTML='',this.button.setAttribute("aria-label",this.closeText),this.insertAdjacentElement("afterbegin",this.button),this.button.addEventListener("click",this.close)}destroyCloseButton(){this.button&&(this.button.removeEventListener("click",this.close),this.button.parentNode.removeChild(this.button),this.button=null)}autoDismiss(){const t=parseInt(this.getAttribute("auto-dismiss"),10);setTimeout(this.close,t>=10?t:3e3)}}customElements.get("joomla-alert")||customElements.define("joomla-alert",t); 2 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-collapse-es5.min.js: -------------------------------------------------------------------------------- 1 | function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){for(var n=0;n { 18 | if (!self.state || (self.state && self.state === 'closed')) { 19 | self.state = 'closed'; 20 | element.setAttribute('aria-expanded', 'false'); 21 | element.setAttribute('aria-controls', self.id); 22 | } else { 23 | element.setAttribute('aria-expanded', 'true'); 24 | element.setAttribute('aria-controls', self.id); 25 | } 26 | 27 | element.addEventListener('click', (event) => { 28 | let colId = ''; 29 | if (!event.target.hasAttribute('data-target')) colId = event.target.getAttribute('href').replace('#', ''); 30 | if (!event.target.hasAttribute('href')) colId = event.target.getAttribute('data-target').replace('#', ''); 31 | event.preventDefault(); 32 | event.stopPropagation(); 33 | document.getElementById(colId).toggle(); 34 | }); 35 | }); 36 | } 37 | 38 | disconnectedCallback() { 39 | let linked = document.querySelector(`[href="#${this.id}"]`); 40 | if (!linked) linked = document.querySelector(`[data-target="#${this.id}"]`); 41 | if (linked) { 42 | linked.removeEventListener('click', this); 43 | } 44 | } 45 | 46 | attributeChangedCallback(attr, oldValue, newValue) { 47 | const linked = document.querySelector(`[href="#${this.id}"]`); 48 | switch (attr) { 49 | case 'state': 50 | if (newValue === 'closed') { 51 | linked.setAttribute('aria-expanded', 'false'); 52 | } else if (newValue === 'open') { 53 | linked.setAttribute('aria-expanded', 'true'); 54 | } 55 | break; 56 | } 57 | } 58 | 59 | toggle() { 60 | let linked = document.querySelector(`[href="#${this.id}"]`); 61 | if (!linked) linked = document.querySelector(`[data-target="#${this.id}"]`); 62 | if (this.state === 'closed') { 63 | this.state = 'open'; 64 | linked.setAttribute('aria-expanded', 'true'); 65 | } else { 66 | this.state = 'closed'; 67 | linked.setAttribute('aria-expanded', 'false'); 68 | } 69 | } 70 | }); 71 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-collapse.min.js: -------------------------------------------------------------------------------- 1 | customElements.define("joomla-collapse",class extends HTMLElement{static get observedAttributes(){return["state"]}get state(){return this.getAttribute("state")}set state(t){this.setAttribute("state",t)}connectedCallback(){const t=this;if(!this.id)return;[].slice.call(document.querySelectorAll(`[href="#${this.id}"],[data-target="#${this.id}"]`)).forEach((e=>{!t.state||t.state&&"closed"===t.state?(t.state="closed",e.setAttribute("aria-expanded","false"),e.setAttribute("aria-controls",t.id)):(e.setAttribute("aria-expanded","true"),e.setAttribute("aria-controls",t.id)),e.addEventListener("click",(t=>{let e="";t.target.hasAttribute("data-target")||(e=t.target.getAttribute("href").replace("#","")),t.target.hasAttribute("href")||(e=t.target.getAttribute("data-target").replace("#","")),t.preventDefault(),t.stopPropagation(),document.getElementById(e).toggle()}))}))}disconnectedCallback(){let t=document.querySelector(`[href="#${this.id}"]`);t||(t=document.querySelector(`[data-target="#${this.id}"]`)),t&&t.removeEventListener("click",this)}attributeChangedCallback(t,e,a){const r=document.querySelector(`[href="#${this.id}"]`);if("state"===t)"closed"===a?r.setAttribute("aria-expanded","false"):"open"===a&&r.setAttribute("aria-expanded","true")}toggle(){let t=document.querySelector(`[href="#${this.id}"]`);t||(t=document.querySelector(`[data-target="#${this.id}"]`)),"closed"===this.state?(this.state="open",t.setAttribute("aria-expanded","true")):(this.state="closed",t.setAttribute("aria-expanded","false"))}}); 2 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-dropdown-es5.min.js: -------------------------------------------------------------------------------- 1 | function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){for(var n=0;n { 26 | if (this.hasAttribute('expanded')) { 27 | this.removeAttribute('expanded'); 28 | event.target.setAttribute('aria-expanded', false); 29 | } else { 30 | this.setAttribute('expanded', ''); 31 | event.target.setAttribute('aria-expanded', true); 32 | } 33 | 34 | document.addEventListener('click', (evt) => { 35 | if (evt.target !== button) { 36 | if (!this.findAncestor(evt.target, 'joomla-dropdown')) { 37 | this.close(); 38 | } 39 | } 40 | }); 41 | 42 | innerLinks.forEach((innerLink) => { 43 | innerLink.addEventListener('click', () => { 44 | this.close(); 45 | }); 46 | }); 47 | }); 48 | } 49 | 50 | /*eslint-disable */ 51 | /* Method to dispatch events */ 52 | dispatchCustomEvent(eventName) { 53 | const OriginalCustomEvent = new CustomEvent(eventName); 54 | OriginalCustomEvent.relatedTarget = this; 55 | this.dispatchEvent(OriginalCustomEvent); 56 | this.removeEventListener(eventName, this); 57 | } 58 | 59 | adoptedCallback(oldDocument, newDocument) { } 60 | 61 | 62 | attributeChangedCallback(attr, oldValue, newValue) { 63 | } 64 | /* eslint-enable */ 65 | 66 | close() { 67 | const button = document.querySelector(`#${this.getAttribute('aria-labelledby')}`); 68 | this.removeAttribute('expanded'); 69 | button.setAttribute('aria-expanded', false); 70 | } 71 | 72 | /* eslint-disable */ 73 | findAncestor(el, tagName) { 74 | while ((el = el.parentElement) && el.nodeName.toLowerCase() !== tagName); 75 | return el; 76 | } 77 | /* eslint-enable */ 78 | } 79 | 80 | customElements.define('joomla-dropdown', JoomlaDropdownElement); 81 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-dropdown.min.js: -------------------------------------------------------------------------------- 1 | class t extends HTMLElement{static get observedAttributes(){return["for"]}get for(){return this.getAttribute("for")}set for(t){this.setAttribute("for",t)}connectedCallback(){this.setAttribute("aria-labelledby",this.for.substring(1));const t=document.querySelector(this.for),e=this.querySelectorAll("a");t.id&&(t.setAttribute("aria-haspopup",!0),t.setAttribute("aria-expanded",!1),t.addEventListener("click",(r=>{this.hasAttribute("expanded")?(this.removeAttribute("expanded"),r.target.setAttribute("aria-expanded",!1)):(this.setAttribute("expanded",""),r.target.setAttribute("aria-expanded",!0)),document.addEventListener("click",(e=>{e.target!==t&&(this.findAncestor(e.target,"joomla-dropdown")||this.close())})),e.forEach((t=>{t.addEventListener("click",(()=>{this.close()}))}))})))}dispatchCustomEvent(t){const e=new CustomEvent(t);e.relatedTarget=this,this.dispatchEvent(e),this.removeEventListener(t,this)}adoptedCallback(t,e){}attributeChangedCallback(t,e,r){}close(){const t=document.querySelector(`#${this.getAttribute("aria-labelledby")}`);this.removeAttribute("expanded"),t.setAttribute("aria-expanded",!1)}findAncestor(t,e){for(;(t=t.parentElement)&&t.nodeName.toLowerCase()!==e;);return t}}customElements.define("joomla-dropdown",t); 2 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-modal.min.js: -------------------------------------------------------------------------------- 1 | const e=9,t=27;customElements.define("joomla-modal",class extends HTMLElement{constructor(){super(),this.triggerBtn="",this.focusableElements=null,this.focusableSelectors=["a[href]","area[href]","input:not([disabled])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex^="-"])'],this.container=this.querySelector(".joomla-modal-dialog")}static get observedAttributes(){return["width","height","innerWidth","innerHeight","iframe"]}connectedCallback(){if(!this.id)throw new Error("`Joomla-modal` requires an id");if(this.title=this.getAttribute("title")||"Modal",this.setAttribute("role","dialog"),this.classList.add("fade"),this.iframe=this.getAttribute("iframe")||"",this.width=this.getAttribute("width")||"100%",this.height=this.getAttribute("height")||"600px",!this.container){const e=document.createElement("div");e.classList.add("joomla-modal-dialog"),e.setAttribute("role","document"),e.innerHTML=this.innerHTML,this.innerHTML="",this.appendChild(e),this.container=this.querySelector(".joomla-modal-dialog")}this.header=this.querySelector("header"),this.main=this.querySelector("section"),this.footer=this.querySelector("footer"),this.setAttribute("tabindex",-1);const e=`modal-title-${(new Date).getUTCMilliseconds()}`;if(this.setAttribute("aria-labelledby",e),!this.header){const t=document.createElement("h5");t.innerText=this.title,t.id=e;const i=document.createElement("button");i.setAttribute("aria-label","Close"),i.setAttribute("data-dismiss",""),i.innerHTML='';const s=document.createElement("header");s.appendChild(t),s.appendChild(i),this.container.insertAdjacentElement("afterbegin",s)}this.header=this.container.querySelector("header"),this.body=this.container.querySelector("section"),this.footer=this.container.querySelector("footer"),this.triggerBtn=document.querySelector(`[data-href="#${this.id}"]`),this.triggerBtn&&this.triggerBtn.addEventListener("click",this.open.bind(this))}disconnectedCallback(){this.triggerBtn&&this.triggerBtn.removeEventListener("click",this.open)}open(){const e=document.createElement("div");if(e.classList.add("modal-backdrop","fade"),e.classList.add("modal-backdrop","show"),document.body.appendChild(e),this.removeAttribute("aria-hidden"),this.body&&(this.iframeEl=this.main.querySelector("iframe"),this.iframe)){this.iframeEl&&this.iframeEl.parentNode.remove(this.iframeEl);const e=document.createElement("iframe");e.width=this.width,e.height=this.height,e.src=this.iframe,e.setAttribute("frameborder",0),this.body.appendChild(e),this.iframeEl=this.main.querySelector("iframe")}this.adjustDimensions(),this.scrollTop=0,this.classList.add("show"),this.focusableElements=[].slice.call(this.querySelectorAll(this.focusableSelectors.join())),this.focusableElements.length?this.focusableElements[0].focus():this.header.querySelector("button").focus(),this.evKeypress=this.keyPress.bind(this),this.evClose=this.close.bind(this),this.evDocumentClose=this.documentClose.bind(this),this.addEventListener("keydown",this.evKeypress),document.addEventListener("click",this.evDocumentClose);[].slice.call(this.querySelectorAll("[data-dismiss]")).forEach((e=>{e.addEventListener("click",this.evClose)}))}close(){this.removeEventListener("keydown",this.evKeypress),document.removeEventListener("click",this.evDocumentClose);[].slice.call(this.querySelectorAll("[data-dismiss]")).forEach((e=>{e.removeEventListener("click",this.evClose)}));const e=document.querySelector(".modal-backdrop");e&&document.body.removeChild(e),this.setAttribute("aria-hidden","true"),this.classList.remove("show"),this.main.innerHTML="",this.triggerBtn.focus()}documentClose(e){this.findAncestorByClass(e.target,"joomla-modal-dialog")||e.target===this.triggerBtn||this.close()}keyPress(i){if(i.keyCode===t&&this.close(),i.keyCode===e){const e=this.focusableElements.indexOf(document.activeElement);!i.shiftKey||0!==e&&-1!==e||(this.focusableElements[this.focusableElements.length-1].focus(),i.preventDefault()),i.shiftKey||e!==this.focusableElements.length-1||(this.focusableElements[0].focus(),i.preventDefault())}}adjustDimensions(){let e=this.offsetHeight;e+=parseInt(window.getComputedStyle(this).getPropertyValue("margin-top"),10),e+=parseInt(window.getComputedStyle(this).getPropertyValue("margin-bottom"),10);const t=this.body.getBoundingClientRect.height;let i=this.body.offsetHeight;i+=parseInt(window.getComputedStyle(this.body).getPropertyValue("margin-top"),10),i+=parseInt(window.getComputedStyle(this.body).getPropertyValue("margin-bottom"),10);let s=this.header.offsetHeight;s+=parseInt(window.getComputedStyle(this.header).getPropertyValue("margin-top"),10),s+=parseInt(window.getComputedStyle(this.header).getPropertyValue("margin-bottom"),10);let o=this.footer.offsetHeight;o+=parseInt(window.getComputedStyle(this.footer).getPropertyValue("margin-top"),10),o+=parseInt(window.getComputedStyle(this.footer).getPropertyValue("margin-bottom"),10);const r=this.offsetTop,n=window.height-2*r,a=i-t,l=n-(s+o+a);if(this.iframeEl){this.iframeEl.getBoundingClientRect().height>l&&(this.container.style.maxHeight=l,this.container.style.overflowY="auto",this.iframeEl.style.maxHeight=l-a)}else e>n&&(this.container.style.maxHeight=l,this.container.style.overflowY="auto")}findAncestorByClass(e,t){for(;(e=e.parentElement)&&!e.classList.contains(t););return e}}); 2 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-tip-es5.min.js: -------------------------------------------------------------------------------- 1 | function t(e){return t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t(e)}function e(t,e){for(var r=0;r').concat(this.tip,"")}},{key:"dispatchCustomEvent",value:function(t){var e=new CustomEvent(t,{bubbles:!0,cancelable:!0});e.relatedTarget=this,this.dispatchEvent(e),this.removeEventListener(t,this)}}],c=[{key:"observedAttributes",get:function(){return["type","label","tip","text","position"]}}],o&&e(n.prototype,o),c&&e(n,c),Object.defineProperty(n,"prototype",{writable:!1}),n;var n,o,c}();customElements.define("joomla-tip",s); 2 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-tip.js: -------------------------------------------------------------------------------- 1 | class TipElement extends HTMLElement { 2 | /* Attributes to monitor */ 3 | static get observedAttributes() { return ['type', 'label', 'tip', 'text', 'position']; } 4 | 5 | get type() { return this.getAttribute('type'); } 6 | 7 | set type(value) { this.setAttribute('type', value); } 8 | 9 | get label() { return this.getAttribute('label'); } 10 | 11 | set label(value) { this.setAttribute('label', value); } 12 | 13 | get tip() { return this.getAttribute('tip'); } 14 | 15 | set tip(value) { this.setAttribute('tip', value); } 16 | 17 | get position() { return this.getAttribute('position'); } 18 | 19 | set position(value) { this.setAttribute('position', value); } 20 | 21 | get text() { return this.getAttribute('text'); } 22 | 23 | set text(value) { this.getAttribute('text', value); } 24 | 25 | /* Lifecycle, element appended to the DOM */ 26 | connectedCallback() { 27 | if (!this.position || (this.position && ['top', 'bottom', 'left', 'right'].indexOf(this.position) === -1)) { 28 | this.position = 'top'; 29 | } 30 | 31 | // create the html 32 | this.btnElement = document.createElement('button'); 33 | this.spanElement = document.createElement('span'); 34 | 35 | this.btnElement.setAttribute('aria-label', this.label ? this.label : 'more info'); 36 | this.btnElement.innerHTML = this.text ? this.text : ''; 37 | this.spanElement.setAttribute('role', 'status'); 38 | 39 | // On click 40 | this.btnElement.addEventListener('click', this.showTip.bind(this)); 41 | 42 | this.append(this.btnElement); 43 | this.append(this.spanElement); 44 | } 45 | 46 | /* Lifecycle, element removed from the DOM */ 47 | disconnectedCallback() { 48 | this.querySelector('button').removeEventListener('click', this.showTip, true); 49 | } 50 | 51 | showTip() { 52 | const self = this; 53 | 54 | // Close on outside click 55 | document.addEventListener('click', (e) => { 56 | if (this.btnElement !== e.target) { 57 | this.spanElement.innerHTML = ''; 58 | self.removeEventListener('keydown', this); 59 | } 60 | }); 61 | 62 | // Remove toggletip on ESC 63 | document.addEventListener('keydown', (e) => { 64 | if ((e.keyCode || e.which) === 9) { 65 | this.spanElement.innerHTML = ''; 66 | self.removeEventListener('keydown', this); 67 | } 68 | }); 69 | 70 | this.spanElement.innerHTML = `${this.tip}`; 71 | } 72 | 73 | /* Method to dispatch events */ 74 | dispatchCustomEvent(eventName) { 75 | const OriginalCustomEvent = new CustomEvent(eventName, { bubbles: true, cancelable: true }); 76 | OriginalCustomEvent.relatedTarget = this; 77 | this.dispatchEvent(OriginalCustomEvent); 78 | this.removeEventListener(eventName, this); 79 | } 80 | } 81 | customElements.define('joomla-tip', TipElement); 82 | -------------------------------------------------------------------------------- /docs/_media/js/joomla-tip.min.js: -------------------------------------------------------------------------------- 1 | class t extends HTMLElement{static get observedAttributes(){return["type","label","tip","text","position"]}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get label(){return this.getAttribute("label")}set label(t){this.setAttribute("label",t)}get tip(){return this.getAttribute("tip")}set tip(t){this.setAttribute("tip",t)}get position(){return this.getAttribute("position")}set position(t){this.setAttribute("position",t)}get text(){return this.getAttribute("text")}set text(t){this.getAttribute("text",t)}connectedCallback(){(!this.position||this.position&&-1===["top","bottom","left","right"].indexOf(this.position))&&(this.position="top"),this.btnElement=document.createElement("button"),this.spanElement=document.createElement("span"),this.btnElement.setAttribute("aria-label",this.label?this.label:"more info"),this.btnElement.innerHTML=this.text?this.text:"",this.spanElement.setAttribute("role","status"),this.btnElement.addEventListener("click",this.showTip.bind(this)),this.append(this.btnElement),this.append(this.spanElement)}disconnectedCallback(){this.querySelector("button").removeEventListener("click",this.showTip,!0)}showTip(){const t=this;document.addEventListener("click",(e=>{this.btnElement!==e.target&&(this.spanElement.innerHTML="",t.removeEventListener("keydown",this))})),document.addEventListener("keydown",(e=>{9===(e.keyCode||e.which)&&(this.spanElement.innerHTML="",t.removeEventListener("keydown",this))})),this.spanElement.innerHTML=`${this.tip}`}dispatchCustomEvent(t){const e=new CustomEvent(t,{bubbles:!0,cancelable:!0});e.relatedTarget=this,this.dispatchEvent(e),this.removeEventListener(t,this)}}customElements.define("joomla-tip",t); 2 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | - Getting started 2 | - [Quick start](/quickstart) 3 | 4 | - Components 5 | - [Alert](/alert) 6 | - [Collapse](/collapse) 7 | - [Dropdown](/dropdown) 8 | - [Modal](/modal) 9 | - [Tab](/tab) 10 | - [Tip](/tip) 11 | 12 | - Customization 13 | - [Theming](/styles) 14 | -------------------------------------------------------------------------------- /docs/collapse.md: -------------------------------------------------------------------------------- 1 | # Collapse WIP 2 | 3 | In order to use the collapse custom element you need to import the element in the document's head: 4 | ```html 5 | 6 | 7 | ``` 8 | 9 | The simplified version of the custom elements 10 | ```html 11 |

12 | 15 | 19 |

20 | 21 |
22 | Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, 23 | craft beer labore wes anderson cred nesciunt sapiente ea proident. 24 |
25 |
26 | ``` 27 | 28 | ### Collapse demo: 29 | 30 |
31 |

32 | 35 | 39 |

40 |
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
41 |
42 | -------------------------------------------------------------------------------- /docs/dropdown.md: -------------------------------------------------------------------------------- 1 | # Dropdown WIP 2 | 3 | In order to use the dropdown custom element you need to import the element in the document's head: 4 | ```html 5 | 6 | 7 | ``` 8 | 9 | The simplified version of the custom elements 10 | ```html 11 |
12 | 13 | 14 | 15 | Item 1 16 | Item 2 17 | Item 3 18 | 19 |
20 | 21 |
22 | 23 | 24 | 25 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

26 |
27 |
28 | ``` 29 | 30 | ### Dropdown demo: 31 | 32 |
33 |
34 | 35 | 36 | Item 1 37 | Item 2 38 | Item 3 39 | 40 |
41 |
42 | 43 | 44 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

45 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Joomla UI components 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 |
33 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /docs/modal.md: -------------------------------------------------------------------------------- 1 | # Modal WIP 2 | 3 | In order to use the modal custom element you need to import the element in the document's head: 4 | ```html 5 | 6 | 7 | ``` 8 | 9 | The simplified version of the custom elements 10 | ```html 11 | 12 | 13 | 14 | 15 |
16 |

I'm a Modal

17 |
18 |
19 | 20 | 21 |
22 |
23 | ``` 24 | 25 | ### Modal demo: 26 |
27 | 28 | 29 |
30 |

I'm a Modal

31 |
32 |
33 | 34 | 35 |
36 |
37 |
38 | 39 | 40 |
41 |

I'm a Modal

42 |
43 |
44 | 45 | 46 |
47 |
48 |
49 | -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | It is recommended to install this repo locally so you can customize the css to match your app/theme/template colours. To do so you can use `npm`: 4 | 5 | ```bash 6 | $ npm i joomla-ui-custom-elements 7 | ``` 8 | 9 | ## Build 10 | 11 | To build the elements just use `grunt`: 12 | 13 | ```bash 14 | $ grunt 15 | ``` 16 | !> So editing the scss files to match your styles and then running `grunt` will produce the elements based on your styles. 17 | 18 | !> You can change the prefix of the element as well, for simplicity this document will refer to elements with the standard prefix `joomla` 19 | 20 | ## Using the elements 21 | 22 | Due to compatibility issues due to browsers support you need to have a polyfill, so your page will render as expected. 23 | The code for this is available from the Polyfills repo on GitHub. Click [here](https://github.com/webcomponents/polyfills) 24 | for full information: 25 | - A shim so ES5 code can run flawlessly into ES6 Browsers 26 | ```html 27 | 28 | ``` 29 | - A polyfill so custom elements can be used in older Browsers 30 | ```html 31 | 32 | ``` 33 | 34 | For each element that you want to use in your page you have to import the relevant CSS and JS file on your page, e.g: 35 | ```html 36 | 37 | 38 | ``` 39 | 40 | ?> The polyfill needs to be inserted only once before the first element. 41 | 42 | ## Customize your elements 43 | 44 | Every element has its own `.scss` file and there is a global `variables.scss` that can be used to tweak the styling to your own needs. Once you've changed the variables re-run `grunt` to rebuild the elements. 45 | 46 | 47 | ## Custom elements are CSS framework agnostic 48 | 49 | Check these collections of custom elements running quite happily with the most popular CSS frameworks: 50 | 51 | ---- 52 | Bootstrap 53 | ----- 54 | Foundation 55 | ----- 56 | UiKit 57 | ----- 58 | -------------------------------------------------------------------------------- /docs/styles.md: -------------------------------------------------------------------------------- 1 | # Customising the look and feel of the components 2 | -------------------------------------------------------------------------------- /docs/sw.js: -------------------------------------------------------------------------------- 1 | /* =========================================================== 2 | * docsify sw.js 3 | * =========================================================== 4 | * Copyright 2016 @huxpro 5 | * Licensed under Apache 2.0 6 | * Register service worker. 7 | * ========================================================== */ 8 | 9 | const RUNTIME = 'docsify' 10 | const HOSTNAME_WHITELIST = [ 11 | self.location.hostname, 12 | 'fonts.gstatic.com', 13 | 'fonts.googleapis.com', 14 | 'unpkg.com' 15 | ] 16 | 17 | // The Util Function to hack URLs of intercepted requests 18 | const getFixedUrl = (req) => { 19 | var now = Date.now() 20 | var url = new URL(req.url) 21 | 22 | // 1. fixed http URL 23 | // Just keep syncing with location.protocol 24 | // fetch(httpURL) belongs to active mixed content. 25 | // And fetch(httpRequest) is not supported yet. 26 | url.protocol = self.location.protocol 27 | 28 | // 2. add query for caching-busting. 29 | // Github Pages served with Cache-Control: max-age=600 30 | // max-age on mutable content is error-prone, with SW life of bugs can even extend. 31 | // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string. 32 | // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190 33 | if (url.hostname === self.location.hostname) { 34 | url.search += (url.search ? '&' : '?') + 'cache-bust=' + now 35 | } 36 | return url.href 37 | } 38 | 39 | /** 40 | * @Lifecycle Activate 41 | * New one activated when old isnt being used. 42 | * 43 | * waitUntil(): activating ====> activated 44 | */ 45 | self.addEventListener('activate', event => { 46 | event.waitUntil(self.clients.claim()) 47 | }) 48 | 49 | /** 50 | * @Functional Fetch 51 | * All network requests are being intercepted here. 52 | * 53 | * void respondWith(Promise r) 54 | */ 55 | self.addEventListener('fetch', event => { 56 | // Skip some of cross-origin requests, like those for Google Analytics. 57 | if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) { 58 | // Stale-while-revalidate 59 | // similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale 60 | // Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1 61 | const cached = caches.match(event.request) 62 | const fixedUrl = getFixedUrl(event.request) 63 | const fetched = fetch(fixedUrl, { cache: 'no-store' }) 64 | const fetchedCopy = fetched.then(resp => resp.clone()) 65 | 66 | // Call respondWith() with whatever we get first. 67 | // If the fetch fails (e.g disconnected), wait for the cache. 68 | // If there’s nothing in cache, wait for the fetch. 69 | // If neither yields a response, return offline pages. 70 | event.respondWith( 71 | Promise.race([fetched.catch(_ => cached), cached]) 72 | .then(resp => resp || fetched) 73 | .catch(_ => { /* eat any errors */ }) 74 | ) 75 | 76 | // Update the cache with the version we fetched (only for ok status) 77 | event.waitUntil( 78 | Promise.all([fetchedCopy, caches.open(RUNTIME)]) 79 | .then(([response, cache]) => response.ok && cache.put(event.request, response)) 80 | .catch(_ => { /* eat any errors */ }) 81 | ) 82 | } 83 | }) 84 | -------------------------------------------------------------------------------- /docs/tip.md: -------------------------------------------------------------------------------- 1 | # Tip WIP 2 | 3 | In order to use the tip custom element you need to import the element in the document's head: 4 | ```html 5 | 6 | 7 | ``` 8 | 9 | The simplified version of the custom elements 10 | ```html 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ``` 23 | 24 | ### tip demo: 25 | 26 | 27 |
28 | 29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /karma-ci.conf.js: -------------------------------------------------------------------------------- 1 | // Browsers to run on Sauce Labs 2 | const customLaunchers = { 3 | SL_chrome: { 4 | base: 'SauceLabs', 5 | browserName: 'chrome', 6 | platform: 'Windows 10', 7 | version: 'latest', 8 | }, 9 | SL_firefox: { 10 | base: 'SauceLabs', 11 | browserName: 'firefox', 12 | version: 'latest', 13 | }, 14 | SL_safari: { 15 | base: 'SauceLabs', 16 | browserName: 'safari', 17 | version: 'latest', 18 | }, 19 | // SL_ie_11: { 20 | // base: 'SauceLabs', 21 | // browserName: 'internet explorer', 22 | // browserVersion: '11.285', 23 | // platformName: 'Windows 10', 24 | // }, 25 | }; 26 | 27 | module.exports = (config) => { 28 | if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) { 29 | console.log('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.'); 30 | process.exit(1); 31 | } 32 | 33 | config.set({ 34 | // list of files / patterns to load in the browser 35 | files: [ 36 | // polyfill 37 | // {pattern: 'node_modules/@webreflection/custom-elements-no-builtin/min.js', served: true, nocache: true }, 38 | // modules 39 | {pattern: 'dist/js/joomla-alert.js', type: 'module' }, 40 | // {pattern: 'dist/js/joomla-collapse.js', type: 'module' }, 41 | // {pattern: 'dist/js/joomla-dropdown.js', type: 'module' }, 42 | // {pattern: 'dist/js/joomla-modal.js', type: 'module' }, 43 | {pattern: 'dist/js/joomla-tab.js', type: 'module' }, 44 | // {pattern: 'dist/js//joomla-tip.js', type: 'module' }, 45 | // ES5 46 | // {pattern: 'dist/js/joomla-alert-es5.js', nomodule: '' }, 47 | // {pattern: 'dist/js/joomla-collapse-es5.js', nomodule: '' }, 48 | // {pattern: 'dist/js/joomla-dropdown-es5.js', nomodule: '' }, 49 | // {pattern: 'dist/js/joomla-modal-es5.js', nomodule: '' }, 50 | // {pattern: 'dist/js/joomla-panels-es5.js', nomodule: '' }, 51 | // {pattern: 'dist/js/joomla-tab-es5.js', nomodule: '' }, 52 | // {pattern: 'dist/js/joomla-tip-es5.js', nomodule: '' }, 53 | 54 | // CSS 55 | 'dist/css/joomla-alert.css', 56 | 'dist/css/joomla-tab.css', 57 | 58 | { pattern: './tests/**/*.js' }, 59 | { pattern: './tests/**/*.html' }, 60 | ], 61 | 62 | preprocessors: { 63 | // 'packags/src/**/js/*.js': ['coverage'], 64 | 'tests/**/*.html': ['html2js'], 65 | }, 66 | plugins: [ 67 | 'karma-sauce-launcher', 68 | 'karma-jasmine', 69 | 'karma-fixture', 70 | 'karma-html2js-preprocessor', 71 | ], 72 | // frameworks to use 73 | frameworks: ['jasmine', 'fixture'], 74 | 75 | // SauceLabs Configuration 76 | sauceLabs: { 77 | testName: 'Web App Unit Tests', 78 | build: `GITHUB #${process.env.GITHUB_RUN_ID} (${process.env.GITHUB_RUN_NUMBER})`, 79 | startConnect: false, 80 | tunnelIdentifier: `github-action-tunnel-custom-elements-${process.env.GITHUB_RUN_ID}`, 81 | }, 82 | 83 | reporters: ['dots', 'saucelabs'], 84 | 85 | // base path that will be used to resolve all patterns (eg. files, exclude) 86 | basePath: process.cwd(), 87 | runnerPort: 9100, 88 | colors: true, 89 | port: 9876, 90 | autoWatch: false, 91 | logLevel: config.LOG_INFO, 92 | singleRun: true, 93 | concurrency: 1, 94 | captureTimeout: 120000, 95 | browserNoActivityTimeout: 60000, 96 | browserDisconnectTimeout: 20000, 97 | browserDisconnectTolerance: 1, 98 | 99 | customLaunchers: customLaunchers, 100 | browsers: Object.keys(customLaunchers), 101 | }); 102 | }; 103 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | module.exports = function (config) { 3 | config.set({ 4 | // frameworks to use 5 | frameworks: ['jasmine', 'fixture'], 6 | 7 | // list of files / patterns to load in the browser 8 | files: [ 9 | // polyfill 10 | // {pattern: 'node_modules/@webreflection/custom-elements-no-builtin/min.js', served: true, nocache: true }, 11 | // modules 12 | {pattern: 'dist/js/joomla-alert.js', type: 'module' }, 13 | // {pattern: 'dist/js/joomla-collapse.js', type: 'module' }, 14 | // {pattern: 'dist/js/joomla-dropdown.js', type: 'module' }, 15 | // {pattern: 'dist/js/joomla-modal.js', type: 'module' }, 16 | // {pattern: 'dist/js/joomla-panels.js', type: 'module' }, 17 | {pattern: 'dist/js/joomla-tab.js', type: 'module' }, 18 | // {pattern: 'dist/js//joomla-tip.js', type: 'module' }, 19 | // ES5 20 | // {pattern: 'dist/js/joomla-alert-es5.js', nomodule: '' }, 21 | // {pattern: 'dist/js/joomla-collapse-es5.js', nomodule: '' }, 22 | // {pattern: 'dist/js/joomla-dropdown-es5.js', nomodule: '' }, 23 | // {pattern: 'dist/js/joomla-modal-es5.js', nomodule: '' }, 24 | // {pattern: 'dist/js/joomla-panels-es5.js', nomodule: '' }, 25 | // {pattern: 'dist/js/joomla-tab-es5.js', nomodule: '' }, 26 | // {pattern: 'dist/js/joomla-tip-es5.js', nomodule: '' }, 27 | 28 | 'dist/css/joomla-alert.css', 29 | 'dist/css/joomla-tab.css', 30 | 31 | { pattern: './tests/**/*.js' }, 32 | { pattern: './tests/**/*.html' }, 33 | ], 34 | 35 | // test results reporter to use 36 | reporters: ['progress'], 37 | 38 | plugins: [ 39 | require('karma-chrome-launcher'), 40 | 'karma-jasmine', 41 | 'karma-fixture', 42 | 'karma-html2js-preprocessor', 43 | ], 44 | 45 | preprocessors: { 46 | // 'packags/src/**/js/*.js': ['coverage'], 47 | 'tests/**/*.html': ['html2js'], 48 | }, 49 | 50 | // base path that will be used to resolve all patterns (eg. files, exclude) 51 | basePath: process.cwd(), 52 | // web server port 53 | port: 9876, 54 | // enable / disable colors in the output (reporters and logs) 55 | colors: true, 56 | // level of logging 57 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 58 | logLevel: config.LOG_INFO, 59 | // enable / disable watching file and executing tests whenever any file changes 60 | autoWatch: true, 61 | // Start these browsers, currently available: 62 | // - Chrome 63 | // - ChromeCanary 64 | // - Firefox 65 | // - Opera 66 | // - Safari (only Mac) 67 | // - PhantomJS 68 | // - IE (only Windows) 69 | browsers: ['ChromeHeadless'], 70 | // Continuous Integration mode 71 | // if true, Karma captures browsers, runs the tests and exits 72 | singleRun: false 73 | }); 74 | }; 75 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "joomla-ui-custom-elements", 3 | "version": "0.4.1", 4 | "description": "Joomla UI components as custom elements", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/joomla-projects/custom-elements.git" 8 | }, 9 | "license": "GPL-2.0-or-later", 10 | "bugs": { 11 | "url": "https://github.com/joomla-projects/custom-elements/issues" 12 | }, 13 | "homepage": "https://github.com/joomla-projects/custom-elements#readme", 14 | "main": "src/index.js", 15 | "keywords": [ 16 | "Joomla", 17 | "web-components", 18 | "custom-elements", 19 | "vanilla-js", 20 | "javascript" 21 | ], 22 | "author": "Dimitrios Grammatikogiannis", 23 | "devDependencies": { 24 | "@babel/core": "7.25.2", 25 | "@babel/preset-env": "7.25.4", 26 | "@rollup/plugin-babel": "6.0.4", 27 | "@rollup/plugin-node-resolve": "15.3.0", 28 | "@rollup/plugin-terser": "0.4.4", 29 | "@webreflection/custom-elements-no-builtin": "0.3.0", 30 | "autoprefixer": "10.4.20", 31 | "cssnano": "7.0.6", 32 | "eslint": "8.57.1", 33 | "eslint-config-airbnb": "19.0.4", 34 | "eslint-config-airbnb-base": "15.0.0", 35 | "eslint-plugin-import": "2.30.0", 36 | "karma": "6.4.4", 37 | "karma-chrome-launcher": "3.2.0", 38 | "karma-fixture": "0.2.6", 39 | "karma-html2js-preprocessor": "1.1.0", 40 | "karma-jasmine": "5.1.0", 41 | "karma-sauce-launcher": "4.3.6", 42 | "postcss": "8.4.47", 43 | "postcss-scss": "^4.0.9", 44 | "rimraf": "6.0.1", 45 | "rollup": "4.22.4", 46 | "rollup-plugin-sass": "1.13.2", 47 | "rollup-plugin-scss": "4.0.0", 48 | "sass": "1.79.3", 49 | "stylelint": "16.9.0", 50 | "stylelint-config-standard": "36.0.1", 51 | "stylelint-order": "6.0.4", 52 | "stylelint-scss": "6.7.0" 53 | }, 54 | "scripts": { 55 | "build": "rimraf dist && node ./node_modules/rollup/dist/bin/rollup -c rollup.config.mjs", 56 | "lint:js": "node ./node_modules/eslint/bin/eslint.js src", 57 | "lint:css": "stylelint --config .stylelintrc.json \"src/scss/**/*.scss\"", 58 | "test": "node node_modules/karma/bin/karma start --single-run --browsers ChromeHeadless karma.conf.js", 59 | "ci-test": "node node_modules/karma/bin/karma start karma-ci.conf.js --single-run", 60 | "browserlist:update": "npx browserslist@latest --update-db" 61 | }, 62 | "overrides": { 63 | "webdriverio": "^7.19.5" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":preserveSemverRanges", 6 | ":disableMajorUpdates" 7 | ], 8 | "versioning": "semver", 9 | "dependencyDashboard": true, 10 | "lockFileMaintenance": { "enabled": true }, 11 | "rangeStrategy": "update-lockfile", 12 | "constraints": { 13 | "npm": "> 8.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 2 | import terser from "@rollup/plugin-terser"; 3 | import { getBabelOutputPlugin } from '@rollup/plugin-babel'; 4 | import sass from 'rollup-plugin-sass'; 5 | import autoprefixer from 'autoprefixer'; 6 | import cssnano from 'cssnano'; 7 | import postcss from 'postcss'; 8 | import { existsSync } from 'fs'; 9 | import { mkdir, writeFile } from 'fs/promises'; 10 | import { dirname } from 'path'; 11 | 12 | const Elements = [ 13 | 'alert', 14 | 'collapse', 15 | 'dropdown', 16 | 'modal', 17 | 'tab', 18 | 'tip', 19 | ]; 20 | 21 | const buildSettings = async () => { 22 | const finalSettings = []; 23 | 24 | Elements.forEach((file) => { 25 | finalSettings.push({ 26 | input: `src/js/${file}/${file}.js`, 27 | plugins: [nodeResolve()], 28 | output: [ 29 | { file: `dist/js/joomla-${file}.js`, format: 'esm' }, 30 | { file: `docs/_media/js/joomla-${file}.js`, format: 'esm' }, 31 | { file: `dist/js/joomla-${file}.min.js`, format: 'esm', plugins: [terser()] }, 32 | { file: `docs/_media/js/joomla-${file}.min.js`, format: 'esm', plugins: [terser()] }, 33 | ], 34 | }); 35 | 36 | finalSettings.push({ 37 | input: `src/js/${file}/${file}.js`, 38 | plugins: [nodeResolve(), getBabelOutputPlugin({ presets: ['@babel/preset-env'] })], 39 | output: [ 40 | { file: `dist/js/joomla-${file}-es5.js`, format: 'esm' }, 41 | { file: `docs/_media/js/joomla-${file}-es5.js`, format: 'esm' }, 42 | { file: `dist/js/joomla-${file}-es5.min.js`, format: 'esm', plugins: [getBabelOutputPlugin({ presets: ['@babel/preset-env'] }), terser()] }, 43 | { file: `docs/_media/js/joomla-${file}-es5.min.js`, format: 'esm', plugins: [getBabelOutputPlugin({ presets: ['@babel/preset-env'] }), terser()] }, 44 | ], 45 | }); 46 | }); 47 | 48 | Elements.forEach((scssFile) => { 49 | finalSettings.push({ 50 | input: `src/scss/${scssFile}/${scssFile}.scss`, 51 | plugins: [ 52 | sass({ 53 | output: false, 54 | processor: css => postcss([autoprefixer]) 55 | .process(css) 56 | .then(async (result) => { 57 | const path1 = `dist/css/joomla-${scssFile}.css`; 58 | const path2 = `docs/_media/css/joomla-${scssFile}.css`; 59 | if (!existsSync(dirname(path1))) { 60 | await mkdir(dirname(path1), {recursive: true}) 61 | } 62 | await writeFile(path1, result.css, {encoding: 'utf8'}); 63 | if (!existsSync(dirname(path2))) { 64 | await mkdir(dirname(path2), {recursive: true}) 65 | } 66 | await writeFile(path2, result.css, {encoding: 'utf8'}); 67 | 68 | postcss([autoprefixer, cssnano]) 69 | .process(result.css) 70 | .then(async (result) => { 71 | const path1 = `dist/css/joomla-${scssFile}.min.css`; 72 | const path2 = `docs/_media/css/joomla-${scssFile}.min.css`; 73 | if (!existsSync(dirname(path1))) { 74 | await mkdir(dirname(path1), {recursive: true}) 75 | } 76 | await writeFile(path1, result.css, {encoding: 'utf8'}); 77 | if (!existsSync(dirname(path2))) { 78 | await mkdir(dirname(path2), {recursive: true}) 79 | } 80 | await writeFile(path2, result.css, {encoding: 'utf8'}); 81 | 82 | }); 83 | }) 84 | }), 85 | ], 86 | }); 87 | }) 88 | 89 | return finalSettings; 90 | }; 91 | 92 | export default buildSettings(); 93 | -------------------------------------------------------------------------------- /src/js/collapse/collapse.js: -------------------------------------------------------------------------------- 1 | customElements.define('joomla-collapse', class extends HTMLElement { 2 | static get observedAttributes() { 3 | return ['state']; 4 | } 5 | 6 | get state() { return this.getAttribute('state'); } 7 | 8 | set state(value) { this.setAttribute('state', value); } 9 | 10 | connectedCallback() { 11 | const self = this; 12 | // id is required 13 | if (!this.id) return; 14 | 15 | const linked = [].slice.call(document.querySelectorAll(`[href="#${this.id}"],[data-target="#${this.id}"]`)); 16 | 17 | linked.forEach((element) => { 18 | if (!self.state || (self.state && self.state === 'closed')) { 19 | self.state = 'closed'; 20 | element.setAttribute('aria-expanded', 'false'); 21 | element.setAttribute('aria-controls', self.id); 22 | } else { 23 | element.setAttribute('aria-expanded', 'true'); 24 | element.setAttribute('aria-controls', self.id); 25 | } 26 | 27 | element.addEventListener('click', (event) => { 28 | let colId = ''; 29 | if (!event.target.hasAttribute('data-target')) colId = event.target.getAttribute('href').replace('#', ''); 30 | if (!event.target.hasAttribute('href')) colId = event.target.getAttribute('data-target').replace('#', ''); 31 | event.preventDefault(); 32 | event.stopPropagation(); 33 | document.getElementById(colId).toggle(); 34 | }); 35 | }); 36 | } 37 | 38 | disconnectedCallback() { 39 | let linked = document.querySelector(`[href="#${this.id}"]`); 40 | if (!linked) linked = document.querySelector(`[data-target="#${this.id}"]`); 41 | if (linked) { 42 | linked.removeEventListener('click', this); 43 | } 44 | } 45 | 46 | attributeChangedCallback(attr, oldValue, newValue) { 47 | const linked = document.querySelector(`[href="#${this.id}"]`); 48 | switch (attr) { 49 | case 'state': 50 | if (newValue === 'closed') { 51 | linked.setAttribute('aria-expanded', 'false'); 52 | } else if (newValue === 'open') { 53 | linked.setAttribute('aria-expanded', 'true'); 54 | } 55 | break; 56 | default: 57 | break; 58 | } 59 | } 60 | 61 | toggle() { 62 | let linked = document.querySelector(`[href="#${this.id}"]`); 63 | if (!linked) linked = document.querySelector(`[data-target="#${this.id}"]`); 64 | if (this.state === 'closed') { 65 | this.state = 'open'; 66 | linked.setAttribute('aria-expanded', 'true'); 67 | } else { 68 | this.state = 'closed'; 69 | linked.setAttribute('aria-expanded', 'false'); 70 | } 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /src/js/dropdown/dropdown.js: -------------------------------------------------------------------------------- 1 | class JoomlaDropdownElement extends HTMLElement { 2 | /* Attributes to monitor */ 3 | static get observedAttributes() { 4 | return ['for']; 5 | } 6 | 7 | get for() { return this.getAttribute('for'); } 8 | set for(value) { this.setAttribute('for', value); } 9 | 10 | connectedCallback() { 11 | this.setAttribute('aria-labelledby', this.for.substring(1)); 12 | const button = document.querySelector(this.for); 13 | const innerLinks = this.querySelectorAll('a'); 14 | 15 | if (!button.id) { 16 | return; 17 | } 18 | // var children = [].slice.call( menu[getElementsByTagName]('*')); 19 | // this.classList.add('dropdown'); 20 | 21 | button.setAttribute('aria-haspopup', true); 22 | button.setAttribute('aria-expanded', false); 23 | 24 | button.addEventListener('click', (event) => { 25 | if (this.hasAttribute('expanded')) { 26 | this.removeAttribute('expanded'); 27 | event.target.setAttribute('aria-expanded', false); 28 | } else { 29 | this.setAttribute('expanded', ''); 30 | event.target.setAttribute('aria-expanded', true); 31 | } 32 | 33 | document.addEventListener('click', (evt) => { 34 | if (evt.target !== button) { 35 | if (!this.findAncestor(evt.target, 'joomla-dropdown')) { 36 | this.close(); 37 | } 38 | } 39 | }); 40 | 41 | innerLinks.forEach((innerLink) => { 42 | innerLink.addEventListener('click', () => { 43 | this.close(); 44 | }); 45 | }); 46 | }); 47 | } 48 | 49 | /*eslint-disable */ 50 | /* Method to dispatch events */ 51 | dispatchCustomEvent(eventName) { 52 | const OriginalCustomEvent = new CustomEvent(eventName); 53 | OriginalCustomEvent.relatedTarget = this; 54 | this.dispatchEvent(OriginalCustomEvent); 55 | this.removeEventListener(eventName, this); 56 | } 57 | 58 | adoptedCallback(oldDocument, newDocument) { } 59 | 60 | 61 | attributeChangedCallback(attr, oldValue, newValue) { 62 | switch (attr) { 63 | // case 'name': 64 | // console.log(newValue); 65 | // break; 66 | } 67 | } 68 | /* eslint-enable */ 69 | 70 | close() { 71 | const button = document.querySelector(`#${this.getAttribute('aria-labelledby')}`); 72 | this.removeAttribute('expanded'); 73 | button.setAttribute('aria-expanded', false); 74 | } 75 | 76 | /* eslint-disable */ 77 | findAncestor(el, tagName) { 78 | while ((el = el.parentElement) && el.nodeName.toLowerCase() !== tagName); 79 | return el; 80 | } 81 | /* eslint-enable */ 82 | } 83 | 84 | customElements.define('joomla-dropdown', JoomlaDropdownElement); 85 | -------------------------------------------------------------------------------- /src/js/tab/tab-element.js: -------------------------------------------------------------------------------- 1 | export class TabElement extends HTMLElement {} 2 | -------------------------------------------------------------------------------- /src/js/tip/tip.js: -------------------------------------------------------------------------------- 1 | class TipElement extends HTMLElement { 2 | /* Attributes to monitor */ 3 | static get observedAttributes() { return ['type', 'label', 'tip', 'text', 'position']; } 4 | 5 | get type() { return this.getAttribute('type'); } 6 | 7 | set type(value) { this.setAttribute('type', value); } 8 | 9 | get label() { return this.getAttribute('label'); } 10 | 11 | set label(value) { this.setAttribute('label', value); } 12 | 13 | get tip() { return this.getAttribute('tip'); } 14 | 15 | set tip(value) { this.setAttribute('tip', value); } 16 | 17 | get position() { return this.getAttribute('position'); } 18 | 19 | set position(value) { this.setAttribute('position', value); } 20 | 21 | get text() { return this.getAttribute('text'); } 22 | 23 | set text(value) { this.getAttribute('text', value); } 24 | 25 | /* Lifecycle, element appended to the DOM */ 26 | connectedCallback() { 27 | if (!this.position || (this.position && ['top', 'bottom', 'left', 'right'].indexOf(this.position) === -1)) { 28 | this.position = 'top'; 29 | } 30 | 31 | // create the html 32 | this.btnElement = document.createElement('button'); 33 | this.spanElement = document.createElement('span'); 34 | 35 | this.btnElement.setAttribute('aria-label', this.label ? this.label : 'more info'); 36 | this.btnElement.innerHTML = this.text ? this.text : ''; 37 | this.spanElement.setAttribute('role', 'status'); 38 | 39 | // On click 40 | this.btnElement.addEventListener('click', this.showTip.bind(this)); 41 | 42 | this.append(this.btnElement); 43 | this.append(this.spanElement); 44 | } 45 | 46 | /* Lifecycle, element removed from the DOM */ 47 | disconnectedCallback() { 48 | this.querySelector('button').removeEventListener('click', this.showTip, true); 49 | } 50 | 51 | showTip() { 52 | const self = this; 53 | 54 | // Close on outside click 55 | document.addEventListener('click', (e) => { 56 | if (this.btnElement !== e.target) { 57 | this.spanElement.innerHTML = ''; 58 | self.removeEventListener('keydown', this); 59 | } 60 | }); 61 | 62 | // Remove toggletip on ESC 63 | document.addEventListener('keydown', (e) => { 64 | if ((e.keyCode || e.which) === 9) { 65 | this.spanElement.innerHTML = ''; 66 | self.removeEventListener('keydown', this); 67 | } 68 | }); 69 | 70 | this.spanElement.innerHTML = `${this.tip}`; 71 | } 72 | 73 | /* Method to dispatch events */ 74 | dispatchCustomEvent(eventName) { 75 | const OriginalCustomEvent = new CustomEvent(eventName, { bubbles: true, cancelable: true }); 76 | OriginalCustomEvent.relatedTarget = this; 77 | this.dispatchEvent(OriginalCustomEvent); 78 | this.removeEventListener(eventName, this); 79 | } 80 | } 81 | customElements.define('joomla-tip', TipElement); 82 | -------------------------------------------------------------------------------- /src/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // 4 | 5 | // Color system 6 | $white: #fff; 7 | $gray-100: #f8f9fa; 8 | $gray-200: #e9ecef; 9 | $gray-300: #dee2e6; 10 | $gray-400: #ced4da; 11 | $gray-500: #adb5bd; 12 | $gray-600: #6c757d; 13 | $gray-700: #495057; 14 | $gray-800: #343a40; 15 | $gray-900: #212529; 16 | $black: #000; 17 | 18 | $blue: #006898; 19 | $indigo: #6610f2; 20 | $purple: #6f42c1; 21 | $pink: #e83e8c; 22 | $red: #d9534f; 23 | $orange: #fd7e14; 24 | $yellow: #f0ad4e; 25 | $green: #438243; 26 | $teal: #20c997; 27 | $cyan: #17a2b8; 28 | 29 | $colors: ( 30 | blue: $blue, 31 | indigo: $indigo, 32 | purple: $purple, 33 | pink: $pink, 34 | red: $red, 35 | orange: $orange, 36 | yellow: $yellow, 37 | green: $green, 38 | teal: $teal, 39 | cyan: $cyan, 40 | white: $white, 41 | gray: $gray-600, 42 | gray-dark: $gray-800 43 | ); 44 | 45 | $theme-colors: ( 46 | primary: $blue, 47 | secondary: $gray-600, 48 | success: $green, 49 | info: $cyan, 50 | warning: $yellow, 51 | danger: $red, 52 | light: $gray-100, 53 | dark: $gray-800 54 | ); 55 | 56 | $alert-colors: ( 57 | success: $green, 58 | info: $cyan, 59 | warning: $yellow, 60 | danger: $red 61 | ); 62 | 63 | $theme-color-interval: 8%; 64 | 65 | // Components 66 | $border-width: 1px; 67 | $border-color: $gray-300; 68 | 69 | $border-radius: .25rem; 70 | $border-radius-lg: .3rem; 71 | $border-radius-sm: .2rem; 72 | 73 | $transition-base: all .2s ease-in-out; 74 | $transition-fade: opacity .15s linear; 75 | $transition-collapse: height .35s ease; 76 | 77 | // Fonts 78 | $font-size-base: 1rem; 79 | 80 | $font-weight-light: 300; 81 | $font-weight-normal: 400; 82 | $font-weight-bold: 700; 83 | 84 | 85 | 86 | // Alerts 87 | $alert-padding-y: .5rem; 88 | $alert-padding-x: 1.25rem; 89 | $alert-margin-bottom: 1rem; 90 | $alert-border-radius: $border-radius; 91 | $alert-link-font-weight: $font-weight-bold; 92 | $alert-border-width: $border-width; 93 | 94 | $alert-bg-level: -10; 95 | $alert-border-level: -9; 96 | $alert-color-level: 6; 97 | 98 | // Close 99 | $close-font-size: $font-size-base * 1.5; 100 | $close-font-weight: $font-weight-bold; 101 | $close-color: $black; 102 | $close-text-shadow: 0 1px 0 $white; 103 | 104 | 105 | 106 | // Tabs 107 | $tab-border-radius: .25rem; 108 | 109 | $tab-ul-bg: #3073bb; 110 | 111 | $tab-link-padding: .75rem 1rem .85rem; 112 | $tab-link-colour: $white; 113 | 114 | $tab-link-width-active: 5px; 115 | $tab-link-bg-colour-active: rgba(0, 0, 0, .2); 116 | 117 | $tab-content-padding: 15px 0; 118 | $tab-content-bg: #fefefe; 119 | 120 | $tab-accordion-link-border: 1px solid #ddd; 121 | 122 | $tab-vertical-ul-border: 1px solid #ccc; 123 | 124 | 125 | 126 | // Dropdown 127 | $dropdown-bg: $white; 128 | $dropdown-border-width: 1px; 129 | $dropdown-border-style: solid; 130 | $dropdown-border-colour: $black; 131 | $dropdown-border-opacity: .15; 132 | 133 | $dropdown-item-padding: .5rem .75rem; 134 | $dropdown-item-bg-hover: $gray-700; 135 | $dropdown-item-color: $gray-900; 136 | $dropdown-item-color-hover: $white; 137 | -------------------------------------------------------------------------------- /src/scss/alert/alert.scss: -------------------------------------------------------------------------------- 1 | joomla-alert { 2 | --jui-alert-min-width: 250px; 3 | --jui-alert-padding: .5rem 1.25rem; 4 | --jui-alert-margin: 0 0 1rem 0; 5 | --jui-alert-border: 1px solid transparent; 6 | --jui-alert-border-radius: .25rem; 7 | --jui-alert-animation-duration: .5s; 8 | --jui-alert-animation-timing-function: ease-in-out; 9 | --jui-alert-button-color-dark: #000; 10 | --jui-alert-button-color-light: #fff; 11 | --jui-alert-success-color: #234423; 12 | --jui-alert-success-background-color: #d9e6d9; 13 | --jui-alert-success-border-color: #cadcca; 14 | --jui-alert-success-link-color: #122212; 15 | --jui-alert-info-color: #0c5460; 16 | --jui-alert-info-background-color: #d1ecf1; 17 | --jui-alert-info-border-color: #bee5eb; 18 | --jui-alert-info-link-color: #062c33; 19 | --jui-alert-warning-color: #7d5a29; 20 | --jui-alert-warning-background-color: #fcefdc; 21 | --jui-alert-warning-border-color: #fbe8cd; 22 | --jui-alert-warning-link-color: #573e1c; 23 | --jui-alert-danger-color: #712b29; 24 | --jui-alert-danger-background-color: #f7dddc; 25 | --jui-alert-danger-border-color: #f4cfce; 26 | --jui-alert-danger-link-color: #4c1d1b; 27 | 28 | display: block; 29 | min-width: var(--jui-alert-min-width, 250px); 30 | padding: var(--jui-alert-padding, .5rem 1.25rem); 31 | margin: var(--jui-alert-margin, 0 0 1rem 0); 32 | border: var(--jui-alert-border, 1px solid transparent); 33 | border-radius: var(--jui-alert-border-radius, .25rem); 34 | animation-duration: var(--jui-alert-animation-duration, .5s); 35 | animation-timing-function: var(--jui-alert-animation-timing-function, ease-in-out); 36 | } 37 | 38 | joomla-alert .joomla-alert--close { 39 | position: relative; 40 | top: -.5rem; 41 | right: -1.25rem; 42 | float: right; 43 | padding: .2rem 1rem; 44 | font-size: 1.5rem; 45 | font-weight: 700; 46 | line-height: 1; 47 | color: var(--jui-alert-button-color-dark, #000); 48 | text-shadow: 0 1px 0 var(--jui-alert-button-color-light, #fff); 49 | background: transparent; 50 | border: 0; 51 | opacity: .5; 52 | } 53 | 54 | joomla-alert .joomla-alert--close:hover, 55 | joomla-alert .joomla-alert--close:focus { 56 | color: var(--jui-alert-button-color-dark, #000); 57 | text-decoration: none; 58 | cursor: pointer; 59 | opacity: .75; 60 | } 61 | 62 | joomla-alert[type=success] { 63 | color: var(--jui-alert-success-color, #234423); 64 | background-color: var(--jui-alert-success-background-color, #d9e6d9); 65 | border-color: var(--jui-alert-success-border-color, #cadcca); 66 | } 67 | 68 | joomla-alert[type=success] hr { 69 | border-top-color: var(--jui-alert-success-border-color, #cadcca); 70 | } 71 | 72 | joomla-alert[type=success] .alert-link { 73 | color: var(--jui-alert-success-link-color, #122212); 74 | } 75 | 76 | joomla-alert[type=info] { 77 | color: var(--jui-alert-info-color, #0c5460); 78 | background-color: var(--jui-alert-info-background-color, #d1ecf1); 79 | border-color: var(--jui-alert-info-border-color, #bee5eb); 80 | } 81 | 82 | joomla-alert[type=info] hr { 83 | border-top-color: var(--jui-alert-info-border-color, #bee5eb); 84 | } 85 | 86 | joomla-alert[type=info] .alert-link { 87 | color: var(--jui-alert-info-link-color, #062c33); 88 | } 89 | 90 | joomla-alert[type=warning] { 91 | color: var(--jui-alert-warning-color, #7d5a29); 92 | background-color: var(--jui-alert-warning-background-color, #fcefdc); 93 | border-color: var(--jui-alert-warning-border-color, #fbe8cd); 94 | } 95 | 96 | joomla-alert[type=warning] hr { 97 | border-top-color: var(--jui-alert-warning-border-color, #fbe8cd); 98 | } 99 | 100 | joomla-alert[type=warning] .alert-link { 101 | color: var(--jui-alert-warning-link-color, #573e1c); 102 | } 103 | 104 | joomla-alert[type=danger] { 105 | color: var(--jui-alert-danger-color, #712b29); 106 | background-color: var(--jui-alert-danger-background-color, #f7dddc); 107 | border-color: var(--jui-alert-danger-border-color, #f4cfce); 108 | } 109 | 110 | joomla-alert[type=danger] hr { 111 | border-top-color: var(--jui-alert-danger-border-color, #f4cfce); 112 | } 113 | 114 | joomla-alert[type=danger] .alert-link { 115 | color: var(--jui-alert-danger-link-color, #4c1d1b); 116 | } 117 | 118 | // RTL overrides 119 | html[dir=rtl] joomla-alert { 120 | .joomla-alert--close, 121 | .joomla-alert-button--close { 122 | right: auto; 123 | left: -1.25rem; 124 | float: left; 125 | } 126 | } 127 | 128 | @keyframes joomla-alert-fade-in { 129 | 0% { opacity: 0; } 130 | } 131 | 132 | @keyframes joomla-alert-fade-out { 133 | 0% { opacity: 1; } 134 | 100% { opacity: 0; } 135 | } 136 | 137 | @media (prefers-reduced-motion: reduce) { 138 | joomla-alert { 139 | animation-duration: 1ms !important; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/scss/collapse/collapse.scss: -------------------------------------------------------------------------------- 1 | // Collapse 2 | 3 | // 4 | // Variables 5 | // 6 | 7 | @import "../variables"; 8 | 9 | 10 | // 11 | // Base styles 12 | // 13 | 14 | joomla-collapse { 15 | 16 | &[state="closed"] { 17 | display: none; 18 | } 19 | 20 | &[state="open"] { 21 | display: block; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/scss/dropdown/dropdown.scss: -------------------------------------------------------------------------------- 1 | // Dropdown 2 | 3 | // 4 | // Variables 5 | // 6 | 7 | @import "../variables"; 8 | 9 | 10 | // 11 | // Base styles 12 | // 13 | 14 | 15 | joomla-dropdown { 16 | position: absolute; 17 | top: 30px; 18 | left: 0; 19 | z-index: 1000; 20 | box-sizing: border-box; 21 | display: none; 22 | min-width: 10rem; 23 | margin-top: .5rem; 24 | font-size: 1rem; 25 | text-align: left; 26 | list-style: none; 27 | background-color: $dropdown-bg; 28 | background-clip: padding-box; 29 | border: $dropdown-border-width $dropdown-border-style rgba($dropdown-border-colour, $dropdown-border-opacity); 30 | 31 | &[expanded] { 32 | display: block; 33 | } 34 | 35 | .dropdown-item { 36 | display: block; 37 | padding: $dropdown-item-padding; 38 | clear: both; 39 | font-weight: $font-weight-normal; 40 | color: $dropdown-item-color; 41 | text-align: inherit; 42 | white-space: nowrap; 43 | background-color: transparent; 44 | border: 0; 45 | 46 | &:hover, 47 | &:focus { 48 | color: $dropdown-item-color-hover; 49 | text-decoration: none; 50 | cursor: pointer; 51 | background: $dropdown-item-bg-hover; 52 | } 53 | } 54 | 55 | } 56 | 57 | .joomla-dropdown-container { 58 | position: relative; 59 | display: inline-flex; 60 | vertical-align: middle; 61 | } 62 | 63 | // RTL overrides 64 | html[dir=rtl] joomla-dropdown { 65 | right: 0; 66 | left: auto; 67 | } 68 | -------------------------------------------------------------------------------- /src/scss/modal/modal.scss: -------------------------------------------------------------------------------- 1 | // Modal 2 | 3 | // 4 | // Variables 5 | // 6 | 7 | @import "../variables"; 8 | 9 | 10 | // 11 | // Base styles 12 | // 13 | 14 | joomla-modal { 15 | position: fixed; 16 | top: 0; 17 | right: 0; 18 | bottom: 0; 19 | left: 0; 20 | z-index: 1050; 21 | box-sizing: inherit; 22 | display: none; 23 | max-width: 500px; 24 | margin: 10px auto; 25 | overflow: hidden; 26 | border-radius: 5px; 27 | outline: 0; 28 | 29 | &.jviewport-width10 { 30 | width: 10vw; 31 | margin-left: -5vw; 32 | } 33 | &.jviewport-width20 { 34 | width: 20vw; 35 | margin-left: -10vw; 36 | } 37 | &.jviewport-width30 { 38 | width: 30vw; 39 | margin-left: -15vw; 40 | } 41 | &.jviewport-width40 { 42 | width: 40vw; 43 | margin-left: -20vw; 44 | } 45 | &.jviewport-width50 { 46 | width: 50vw; 47 | margin-left: -25vw; 48 | } 49 | &.jviewport-width60 { 50 | width: 60vw; 51 | margin-left: -30vw; 52 | } 53 | &.jviewport-width70 { 54 | width: 70vw; 55 | margin-left: -35vw; 56 | } 57 | &.jviewport-width80 { 58 | width: 80vw; 59 | margin-left: -40vw; 60 | } 61 | &.jviewport-width90 { 62 | width: 90vw; 63 | margin-left: -45vw; 64 | } 65 | &.jviewport-width100 { 66 | width: 100vw; 67 | margin-left: -50vw; 68 | } 69 | 70 | &.show { 71 | display: block; 72 | } 73 | 74 | .joomla-modal-dialog { 75 | position: relative; 76 | display: flex; 77 | flex-direction: column; 78 | background-color: #fff; 79 | background-clip: padding-box; 80 | border: 1px solid rgba(0, 0, 0, .2); 81 | border-radius: .3rem; 82 | outline: 0; 83 | 84 | &.fade { 85 | opacity: 0; 86 | transition: opacity .15s linear; 87 | } 88 | 89 | &.fade.show { 90 | opacity: 1; 91 | } 92 | 93 | header { 94 | display: flex; 95 | align-items: center; 96 | justify-content: space-between; 97 | padding: 15px; 98 | border-bottom: 1px solid #e9ecef; 99 | 100 | button { 101 | float: right; 102 | padding: 0; 103 | font-size: 1.5rem; 104 | font-weight: 700; 105 | line-height: 1; 106 | color: #000; 107 | text-shadow: 0 1px 0 #fff; 108 | cursor: pointer; 109 | background: 0 0; 110 | border: 0; 111 | opacity: .5; 112 | appearance: none; 113 | } 114 | 115 | h5 { 116 | margin-bottom: 0; 117 | font-size: 1.25rem; 118 | line-height: 1.5; 119 | } 120 | } 121 | 122 | section { 123 | position: relative; 124 | flex: 1 1 auto; 125 | padding: 15px; 126 | 127 | &.jviewport-height10 { 128 | height: 10vh; 129 | } 130 | &.jviewport-height20 { 131 | height: 20vh; 132 | } 133 | &.jviewport-height30 { 134 | height: 30vh; 135 | } 136 | &.jviewport-height40 { 137 | height: 40vh; 138 | } 139 | &.jviewport-height50 { 140 | height: 50vh; 141 | } 142 | &.jviewport-height60 { 143 | height: 60vh; 144 | } 145 | &.jviewport-height70 { 146 | height: 70vh; 147 | } 148 | &.jviewport-height80 { 149 | height: 80vh; 150 | } 151 | &.jviewport-height90 { 152 | height: 90vh; 153 | } 154 | &.jviewport-height100 { 155 | height: 100vh; 156 | } 157 | } 158 | 159 | section[class^="jviewport-height"], 160 | section[class*="jviewport-height"] { 161 | max-height: none; 162 | } 163 | 164 | footer { 165 | display: flex; 166 | align-items: center; 167 | justify-content: flex-end; 168 | padding: 15px; 169 | border-top: 1px solid #e9ecef; 170 | 171 | .btn { 172 | margin-left: 10px; 173 | } 174 | } 175 | } 176 | } 177 | 178 | .modal-backdrop.show { 179 | opacity: .5; 180 | } 181 | .modal-backdrop { 182 | position: fixed; 183 | top: 0; 184 | right: 0; 185 | bottom: 0; 186 | left: 0; 187 | z-index: 1040; 188 | background-color: #000; 189 | } 190 | -------------------------------------------------------------------------------- /src/scss/tab/tab.scss: -------------------------------------------------------------------------------- 1 | // Tabs 2 | 3 | // 4 | // Variables 5 | // 6 | 7 | @import "../variables"; 8 | 9 | 10 | // 11 | // Base styles 12 | // 13 | 14 | joomla-tab { 15 | display: flex; 16 | flex-direction: column; 17 | } 18 | 19 | joomla-tab[view=tabs] > div[role=tablist] { 20 | display: flex; 21 | padding: 0; 22 | margin: 0; 23 | overflow-x: auto; 24 | overflow-y: hidden; 25 | white-space: nowrap; 26 | list-style: outside none none; 27 | background-color: #f5f5f5; 28 | border-color: #ccc #ccc currentcolor; 29 | border-style: solid solid none; 30 | border-width: 1px 1px 0; 31 | border-radius: .25rem .25rem 0 0; 32 | border-image: none; 33 | box-shadow: 0 1px #fff inset, 0 2px 3px -3px rgba(0, 0, 0, .15), 0 -4px 0 rgba(0, 0, 0, .05) inset, 0 0 3px rgba(0, 0, 0, .04); 34 | } 35 | 36 | joomla-tab[view=accordion] > div[role=tablist] { 37 | display: none; 38 | } 39 | 40 | joomla-tab button[role=tab] { 41 | position: relative; 42 | display: block; 43 | padding: .75em 1em; 44 | color: #0d1321; 45 | text-decoration: none; 46 | background-color: transparent; 47 | border: unset; 48 | box-shadow: 1px 0 0 rgba(0, 0, 0, .05); 49 | appearance: none; 50 | } 51 | 52 | joomla-tab button[role=tab][aria-expanded="true"], 53 | joomla-tab button[role=tab][aria-selected="true"] { 54 | background-color: rgba(0, 0, 0, .03); 55 | background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, .05) 100%); 56 | border-right: 0 none; 57 | border-left: 0 none; 58 | border-top-left-radius: 0; 59 | border-top-right-radius: 0; 60 | box-shadow: 2px 0 1px -1px rgba(0, 0, 0, .08) inset, -2px 0 1px -1px rgba(0, 0, 0, .08) inset, 0 1px 0 rgba(0, 0, 0, .02) inset; 61 | } 62 | 63 | joomla-tab button[aria-expanded="true"]::after, 64 | joomla-tab button[aria-selected="true"]::after 65 | { 66 | position: absolute; 67 | right: 0; 68 | bottom: -1px; 69 | left: 0; 70 | height: 5px; 71 | content: ""; 72 | background-color: #006898; 73 | opacity: .8; 74 | } 75 | 76 | joomla-tab > joomla-tab-element { 77 | position: relative; 78 | display: none; 79 | padding: 15px; 80 | background-color: #fefefe; 81 | border: 1px solid #ccc; 82 | border-radius: 0 0 .25rem .25rem; 83 | box-shadow: 0 0 3px rgba(0, 0, 0, .04); 84 | } 85 | 86 | joomla-tab > joomla-tab-element[active] { 87 | display: block; 88 | } 89 | 90 | joomla-tab[orientation=vertical] { 91 | flex-direction: row; 92 | align-items: flex-start; 93 | } 94 | 95 | joomla-tab[orientation=vertical] > div[role=tablist] { 96 | flex-direction: column; 97 | min-width: 30%; 98 | height: auto; 99 | overflow: hidden; 100 | border: 1px solid #ccc; 101 | border-radius: .25rem; 102 | box-shadow: none; 103 | } 104 | 105 | joomla-tab[orientation=vertical] > div[role=tablist] button:last-of-type { 106 | border-bottom: 0; 107 | } 108 | 109 | joomla-tab[orientation=vertical] > div[role=tablist] button { 110 | position: relative; 111 | display: block; 112 | padding: .75em 1em; 113 | color: #0d1321; 114 | text-decoration: none; 115 | background-color: transparent; 116 | border-bottom: 1px solid #ddd; 117 | box-shadow: none; 118 | appearance: none; 119 | } 120 | 121 | joomla-tab[orientation=vertical] > div[role=tablist] button[aria-expanded="true"] { 122 | background-color: #fff; 123 | background-image: none; 124 | border-right: 0 none; 125 | border-left: 0 none; 126 | box-shadow: none; 127 | } 128 | 129 | joomla-tab[orientation=vertical] > div[role=tablist] button[aria-expanded="true"]::after { 130 | top: 0; 131 | bottom: 0; 132 | left: -1px; 133 | width: 5px; 134 | height: auto; 135 | } 136 | 137 | joomla-tab[orientation=vertical] > joomla-tab-element { 138 | padding: 15px; 139 | border: 0 none; 140 | box-shadow: none; 141 | } 142 | 143 | joomla-tab[view=accordion] { 144 | flex-direction: column; 145 | white-space: normal; 146 | border-radius: .25rem; 147 | box-shadow: 0 1px #fff inset, 0 0 3px rgba(0, 0, 0, .04); 148 | 149 | > button { 150 | position: relative; 151 | display: block; 152 | padding: .75em 1em; 153 | color: #0d1321; 154 | text-decoration: none; 155 | background-color: #f5f5f5; 156 | border: unset; 157 | box-shadow: 1px 0 0 rgba(0, 0, 0, .05); 158 | appearance: none; 159 | 160 | &[aria-expanded=true], 161 | &:focus { 162 | background-color: rgba(0, 0, 0, .03); 163 | background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, .05) 100%); 164 | } 165 | } 166 | } 167 | 168 | joomla-tab[view=accordion] joomla-tab-element { 169 | display: none; 170 | padding: 15px; 171 | } 172 | 173 | joomla-tab[view=accordion] joomla-tab-element[active] { 174 | display: block; 175 | border-bottom: 1px solid #ddd; 176 | } 177 | 178 | joomla-tab[view=accordion] [active] { 179 | background-color: #fff; 180 | } 181 | 182 | joomla-tab[view=accordion] button { 183 | appearance: none; 184 | border-bottom: 1px solid #ddd; 185 | } 186 | 187 | joomla-tab[view=accordion] button[aria-expanded="true"]::after { 188 | top: 0; 189 | left: 0; 190 | width: 5px; 191 | height: 100%; 192 | } 193 | -------------------------------------------------------------------------------- /src/scss/tip/tip.scss: -------------------------------------------------------------------------------- 1 | // Tooltip 2 | 3 | // 4 | // Variables 5 | // 6 | 7 | @import "../variables"; 8 | 9 | 10 | // 11 | // Base styles 12 | // 13 | 14 | joomla-tip { 15 | position: relative; 16 | display: inline-block; 17 | 18 | button { 19 | width: 1.6rem; 20 | height: 1.6rem; 21 | font-family: serif; 22 | font-size: 1.4rem; 23 | font-weight: bold; 24 | line-height: 1.4rem; 25 | color: #fff; 26 | background: #1c3d5c; 27 | border: 0; 28 | border-radius: 50%; 29 | } 30 | 31 | .toggletip-bubble { 32 | position: absolute; 33 | z-index: 1040; 34 | display: inline-block; 35 | width: 14rem; 36 | padding: .5rem .8rem; 37 | font-size: .9rem; 38 | line-height: 1.2rem; 39 | color: #fff; 40 | background: #222; 41 | border-radius: .25rem; 42 | box-shadow: 0 0 5px rgba(0,0,0,.4); 43 | transition: all ease-in; 44 | animation-duration: .3s; 45 | 46 | &::after { 47 | position: absolute; 48 | top: .6rem; 49 | right: 100%; 50 | width: 0; 51 | height: 0; 52 | content: ""; 53 | border-style: solid; 54 | } 55 | 56 | &.top { 57 | bottom: 100%; 58 | left: 50%; 59 | margin-bottom: .6rem; 60 | transform: translate(-50%, 0); 61 | animation-name: toggletip-fadeInTop; 62 | 63 | &::after { 64 | top: 100%; 65 | bottom: auto; 66 | left: 50%; 67 | border-color: #222 transparent transparent; 68 | border-width: 6px 6px 0; 69 | transform: translateX(-50%); 70 | } 71 | 72 | } 73 | 74 | &.left { 75 | top: 50%; 76 | right: 100%; 77 | margin-right: .6rem; 78 | transform: translate(0, -50%); 79 | animation-name: toggletip-fadeInLeft; 80 | 81 | &::after { 82 | top: 50%; 83 | bottom: auto; 84 | left: 100%; 85 | border-color: transparent transparent transparent #222; 86 | border-width: 6px 0 6px 6px; 87 | transform: translateY(-50%); 88 | } 89 | 90 | } 91 | 92 | &.right { 93 | top: 50%; 94 | left: 100%; 95 | margin-left: .6rem; 96 | transform: translate(0, -50%); 97 | animation-name: toggletip-fadeInRight; 98 | 99 | &::after { 100 | top: 50%; 101 | right: 100%; 102 | bottom: auto; 103 | border-color: transparent #222 transparent transparent; 104 | border-width: 6px 6px 6px 0; 105 | transform: translateY(-50%); 106 | } 107 | 108 | } 109 | 110 | &.bottom { 111 | top: 100%; 112 | left: 50%; 113 | margin-top: .6rem; 114 | transform: translate(-50%, 0); 115 | animation-name: toggletip-fadeInBottom; 116 | 117 | &::after { 118 | top: -6px; 119 | left: 50%; 120 | border-color: transparent transparent #222; 121 | border-width: 0 6px 6px; 122 | transform: translateX(-50%); 123 | } 124 | 125 | } 126 | 127 | } 128 | 129 | } 130 | 131 | @keyframes toggletip-fadeInRight { 132 | from { 133 | opacity: 0; 134 | transform: translate(-10px, -50%); 135 | } 136 | to { 137 | opacity: 1; 138 | transform: translate(0, -50%); 139 | } 140 | } 141 | @keyframes toggletip-fadeInLeft { 142 | from { 143 | opacity: 0; 144 | transform: translate(10px, -50%); 145 | } 146 | to { 147 | opacity: 1; 148 | transform: translate(0, -50%); 149 | } 150 | } 151 | @keyframes toggletip-fadeInTop { 152 | from { 153 | opacity: 0; 154 | transform: translate(-50%, 10px); 155 | } 156 | to { 157 | opacity: 1; 158 | transform: translate(-50%, 0); 159 | } 160 | } 161 | @keyframes toggletip-fadeInBottom { 162 | from { 163 | opacity: 0; 164 | transform: translate(-50%, -10px); 165 | } 166 | to { 167 | opacity: 1; 168 | transform: translate(-50%, 0); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /tests/alert/alert.html: -------------------------------------------------------------------------------- 1 | 2 |

Has some text

3 |
4 | -------------------------------------------------------------------------------- /tests/alert/test.js: -------------------------------------------------------------------------------- 1 | describe('', function(){ 2 | beforeEach(function() { 3 | fixture.setBase('tests/alert'); 4 | fixture.load('alert.html', true); 5 | }); 6 | afterEach(function() { 7 | fixture.cleanup(); 8 | }); 9 | 10 | it('Custom Element script is loaded', function(){ 11 | expect(customElements.get('joomla-alert')).toBeTrue; 12 | }); 13 | 14 | it('Has type info', function() { 15 | const type = fixture.el.firstElementChild.getAttribute('type') 16 | 17 | expect(type).toEqual('info'); 18 | }); 19 | 20 | it('Respects type attribute change, any unsupported value', function() { 21 | fixture.el.firstElementChild.setAttribute('type', 'unknown'); 22 | const type = fixture.el.firstElementChild.getAttribute('type'); 23 | 24 | expect(type).toEqual('info'); 25 | }); 26 | 27 | it('Respects type attribute change, warning', function() { 28 | fixture.el.firstElementChild.setAttribute('type', 'warning'); 29 | const type = fixture.el.firstElementChild.getAttribute('type'); 30 | 31 | expect(type).toEqual('warning'); 32 | }); 33 | 34 | it('Respects type attribute change, danger', function() { 35 | fixture.el.firstElementChild.setAttribute('type', 'danger'); 36 | const type = fixture.el.firstElementChild.getAttribute('type'); 37 | 38 | expect(type).toEqual('danger'); 39 | }); 40 | 41 | it('Respects type attribute change, success', function() { 42 | fixture.el.firstElementChild.setAttribute('type', 'success'); 43 | const type = fixture.el.firstElementChild.getAttribute('type'); 44 | 45 | expect(type).toEqual('success'); 46 | }); 47 | 48 | it('Has the right text', function() { 49 | const type = fixture.el.firstElementChild.querySelector('#text').innerText; 50 | 51 | expect(type).toEqual('Has some text'); 52 | }); 53 | }); 54 | 55 | describe('', function(){ 56 | beforeEach(function() { 57 | fixture.setBase('tests/alert'); 58 | fixture.load('alert.html', true); 59 | }); 60 | afterEach(function() { 61 | fixture.cleanup(); 62 | }); 63 | 64 | it('Has close button', function() { 65 | const type = fixture.el.firstElementChild.hasAttribute('dismiss'); 66 | 67 | expect(type).toBeTrue; 68 | }); 69 | 70 | it('Respects button attribute change, false', function() { 71 | const el = fixture.el.firstElementChild; 72 | el.setAttribute('dismiss', 'false'); 73 | const type = el.getAttribute('dismiss'); 74 | const closeBtn = el.querySelectorAll('.joomla-alert--close'); 75 | const close = el.querySelectorAll('button'); 76 | expect(type).toBe('false'); 77 | expect(closeBtn.length === 0).toBeTrue; 78 | expect(close.length === 0).toBeTrue(); 79 | }); 80 | 81 | it('Respects button attribute change, true', function() { 82 | const el = fixture.el.firstElementChild; 83 | el.setAttribute('dismiss', 'true'); 84 | const type = el.getAttribute('dismiss'); 85 | const closeBtn = el.querySelectorAll('.joomla-alert--close'); 86 | const close = el.querySelectorAll('button'); 87 | expect(type).toBe('true'); 88 | expect(closeBtn.length === 1).toBeTrue; 89 | expect(close.length === 1).toBeTrue(); 90 | }); 91 | 92 | it('Method close removes the alert', function() { 93 | const el = fixture.el.firstElementChild; 94 | el.close(); 95 | const type = el.querySelector('joomla-alert'); 96 | 97 | expect(type).toBe(null); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /tests/tab/tab.html: -------------------------------------------------------------------------------- 1 | 2 | First tab content 3 | 4 | Second tab content 5 | 6 | Third tab content 7 | 8 | --------------------------------------------------------------------------------