├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── .modernizrrc.js
├── .prettierignore
├── .release-it.js
├── CHANGES.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── Makefile
├── README.md
├── RELEASE.md
├── _sass
├── _fonts.scss
├── _mixins.scss
├── _patterns.scss
├── _settings.scss
└── components
│ ├── _avatar.scss
│ ├── _button-bar.scss
│ ├── _button.scss
│ ├── _form.scss
│ ├── _icon.scss
│ ├── _photoswipe.scss
│ └── _tiny-content.scss
├── babel.config.js
├── commitlint.config.js
├── docs
├── designer
│ ├── markup-styleguide.md
│ ├── parameters.md
│ ├── tips-and-tricks.md
│ └── what-is-patternslib.md
├── developer
│ ├── create-a-pattern.md
│ ├── module-federation.md
│ ├── parser.md
│ ├── patterns.rst
│ ├── store.md
│ ├── styleguide.md
│ └── usage-recipies.md
└── history
│ ├── 1.md
│ ├── 2.md
│ ├── 3.md
│ ├── 4.md
│ ├── 5.md
│ ├── 6.md
│ ├── 7.md
│ ├── 8.md
│ ├── UPGRADE-2-TO-3.md
│ └── index.md
├── eslint.config.js
├── index.html
├── jest.config.js
├── package.json
├── prettier.config.js
├── src
├── core
│ ├── base.js
│ ├── base.test.js
│ ├── basepattern.js
│ ├── basepattern.md
│ ├── basepattern.test.js
│ ├── dom.js
│ ├── dom.test.js
│ ├── events.js
│ ├── events.test.js
│ ├── feature-detection.js
│ ├── feature-detection.md
│ ├── i18n.js
│ ├── jquery-ext.js
│ ├── jquery-ext.test.js
│ ├── logging.js
│ ├── mockup-parser.js
│ ├── parser.js
│ ├── parser.test.js
│ ├── polyfills.js
│ ├── polyfills.test.js
│ ├── push_kit.js
│ ├── registry.js
│ ├── registry.test.js
│ ├── remove.js
│ ├── store.js
│ ├── store.test.js
│ ├── url.js
│ ├── url.test.js
│ ├── utils.js
│ ├── utils.test.js
│ ├── uuid.js
│ └── uuid.test.js
├── index.js
├── lib
│ ├── depends_parse.js
│ ├── depends_parse.pegjs
│ ├── depends_parse.test.js
│ ├── dependshandler.js
│ ├── dependshandler.test.js
│ └── input-change-events.js
├── pat
│ ├── ajax
│ │ ├── ajax.js
│ │ └── ajax.test.js
│ ├── auto-scale
│ │ ├── _auto-scale.scss
│ │ ├── auto-scale.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── auto-submit
│ │ ├── auto-submit.js
│ │ ├── auto-submit.test.js
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── pattern-test-response.html
│ │ └── placeholder.gif
│ ├── auto-suggest
│ │ ├── _auto-suggest.scss
│ │ ├── auto-suggest.js
│ │ ├── auto-suggest.test.js
│ │ ├── data.json
│ │ ├── datagroup.json
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── select2-spinner.gif
│ │ ├── select2.png
│ │ └── select2x2.png
│ ├── autofocus
│ │ ├── autofocus.js
│ │ ├── autofocus.test.js
│ │ ├── documentation.md
│ │ ├── index-iframed.html
│ │ └── index.html
│ ├── breadcrumbs
│ │ └── breadcrumbs.js
│ ├── bumper
│ │ ├── bumper.js
│ │ ├── bumper.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── calendar
│ │ ├── calendar.js
│ │ ├── calendar.test.js
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── test_add_event.html
│ │ ├── test_event.html
│ │ ├── test_event_source.json
│ │ └── test_event_source2.json
│ ├── carousel
│ │ ├── _carousel.scss
│ │ ├── ajax-loader.gif
│ │ ├── carousel-arrows.png
│ │ ├── carousel-arrows.psd
│ │ ├── carousel.js
│ │ ├── carousel.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── checklist
│ │ ├── _checklist.scss
│ │ ├── checklist.js
│ │ ├── checklist.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── clone-code
│ │ ├── clone-code.js
│ │ ├── clone-code.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── clone
│ │ ├── clone.js
│ │ ├── clone.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── close-panel
│ │ ├── close-panel.js
│ │ ├── close-panel.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── collapsible
│ │ ├── _collapsible.scss
│ │ ├── collapsible-sources.html
│ │ ├── collapsible.js
│ │ ├── collapsible.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── colour-picker
│ │ ├── _colour-picker.scss
│ │ ├── colour-picker.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── date-picker
│ │ ├── _date-picker.scss
│ │ ├── date-picker.js
│ │ ├── date-picker.test.js
│ │ ├── documentation.md
│ │ ├── i18n.json
│ │ └── index.html
│ ├── datetime-picker
│ │ ├── _datetime-picker.scss
│ │ ├── datetime-picker.js
│ │ ├── datetime-picker.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── depends
│ │ ├── depends.js
│ │ ├── depends.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── display-time
│ │ ├── display-time.js
│ │ ├── display-time.test.js
│ │ ├── documentation.md
│ │ └── index.html
│ ├── equaliser
│ │ ├── _equaliser.scss
│ │ ├── documentation.md
│ │ ├── equaliser.js
│ │ ├── equaliser.test.js
│ │ └── index.html
│ ├── expandable-tree
│ │ ├── _expandable-tree.scss
│ │ ├── documentation.md
│ │ ├── expandable-tree.js
│ │ └── index.html
│ ├── focus
│ │ ├── _focus.scss
│ │ ├── documentation.md
│ │ ├── focus.js
│ │ ├── focus.test.js
│ │ └── index.html
│ ├── form-state
│ │ └── form-state.js
│ ├── forward
│ │ ├── documentation.md
│ │ ├── forward.js
│ │ ├── forward.test.js
│ │ └── index.html
│ ├── fullscreen
│ │ ├── _fullscreen.scss
│ │ ├── documentation.md
│ │ ├── fullscreen-close.js
│ │ ├── fullscreen.js
│ │ ├── fullscreen.test.js
│ │ └── index.html
│ ├── gallery
│ │ ├── _gallery.scss
│ │ ├── default-skin.png
│ │ ├── default-skin.svg
│ │ ├── documentation.md
│ │ ├── full-1.jpg
│ │ ├── full-2.jpg
│ │ ├── full-3.jpg
│ │ ├── full-4.jpg
│ │ ├── gallery.js
│ │ ├── gallery.test.js
│ │ ├── icons.png
│ │ ├── icons@2x.png
│ │ ├── index.html
│ │ ├── loader.gif
│ │ ├── preloader.gif
│ │ ├── template.html
│ │ ├── thumb-1.jpg
│ │ ├── thumb-2.jpg
│ │ └── thumb-3.jpg
│ ├── grid
│ │ ├── _grid.scss
│ │ ├── documentation.md
│ │ ├── grid.js
│ │ ├── index.html
│ │ ├── offsets.png
│ │ └── source-ordering.png
│ ├── image-crop
│ │ ├── Jcrop.gif
│ │ ├── _image-crop.scss
│ │ ├── documentation.md
│ │ ├── image-crop.js
│ │ ├── image-crop.test.js
│ │ ├── index.html
│ │ └── pool.jpg
│ ├── inject
│ │ ├── _inject.scss
│ │ ├── _injection.scss
│ │ ├── demo
│ │ │ ├── backend-action.html
│ │ │ ├── cocteau.jpg
│ │ │ ├── history-inject-source.html
│ │ │ ├── history-page1.html
│ │ │ ├── history-page2.html
│ │ │ ├── history-page3.html
│ │ │ ├── history.html
│ │ │ ├── inject-form.html
│ │ │ ├── inject-sources.html
│ │ │ ├── inject-text.html
│ │ │ ├── pattern-test-response.html
│ │ │ ├── rilke.jpg
│ │ │ ├── test_404.html
│ │ │ └── wilde.jpg
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── inject.js
│ │ ├── inject.test.js
│ │ ├── injection-modal.svg
│ │ ├── injection-multiple.svg
│ │ └── injection-single.svg
│ ├── legend
│ │ ├── legend.js
│ │ └── legend.test.js
│ ├── markdown
│ │ ├── content
│ │ │ ├── content
│ │ │ └── content.md
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── markdown.js
│ │ └── markdown.test.js
│ ├── masonry
│ │ ├── README.md
│ │ ├── _masonry.scss
│ │ ├── documentation.md
│ │ ├── images
│ │ │ ├── bouquet.jpg
│ │ │ ├── flower-of-happiness.jpg
│ │ │ ├── lillies.jpg
│ │ │ ├── petunia.jpg
│ │ │ └── woolflowers.jpg
│ │ ├── index.html
│ │ ├── masonry.js
│ │ └── masonry.test.js
│ ├── menu
│ │ ├── _menu.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── menu.js
│ │ └── menu.test.js
│ ├── minimalpattern
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── minimalpattern.js
│ │ └── minimalpattern.test.js
│ ├── modal
│ │ ├── _modal.scss
│ │ ├── buttons-modal.png
│ │ ├── documentation.md
│ │ ├── index-modal.html
│ │ ├── index.html
│ │ ├── modal.js
│ │ └── modal.test.js
│ ├── navigation
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── navigation.js
│ │ └── navigation.test.js
│ ├── notification
│ │ ├── _notification.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── inject-notification.html
│ │ ├── inject-source.html
│ │ ├── notification.js
│ │ └── notification.test.js
│ ├── push
│ │ ├── documentation.md
│ │ ├── index-push-content.html
│ │ ├── index-push-messages.html
│ │ ├── index.html
│ │ ├── push.js
│ │ └── tools
│ │ │ ├── .gitignore
│ │ │ ├── Makefile
│ │ │ ├── README.md
│ │ │ ├── rabbitmq_enabled_plugins
│ │ │ └── send.py
│ ├── scroll-box
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── scroll-box.js
│ │ └── scroll-box.test.js
│ ├── scroll-marker
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── scroll-marker.js
│ │ └── scroll-marker.test.js
│ ├── scroll
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── scroll.js
│ │ ├── scroll.test.js
│ │ ├── scrollcalculation.svg
│ │ └── test-scrollbody.html
│ ├── selectbox
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── selectbox.js
│ │ └── selectbox.test.js
│ ├── separator
│ │ └── _separator.scss
│ ├── slides
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── media
│ │ │ ├── binnenhof.jpg
│ │ │ ├── chrome-gradient-fix.png
│ │ │ ├── dialogues.jpg
│ │ │ ├── joker.png
│ │ │ ├── logo-rijksoverheid-dp.svg
│ │ │ ├── pearl-bar.jpg
│ │ │ ├── pearl-jewel.png
│ │ │ ├── pearl-model-fingers.png
│ │ │ ├── pearl-model.png
│ │ │ ├── pearl-pearl.png
│ │ │ └── pearl-slogan.png
│ │ ├── notes.md
│ │ ├── slides.js
│ │ ├── slides.test.js
│ │ ├── standalone-test.html
│ │ └── style
│ │ │ ├── animate.css
│ │ │ ├── README.md
│ │ │ ├── animate.css
│ │ │ └── animate.min.css
│ │ │ ├── fontello
│ │ │ ├── LICENSE.txt
│ │ │ ├── README.txt
│ │ │ ├── config.json
│ │ │ ├── css
│ │ │ │ ├── animation.css
│ │ │ │ ├── fontello-codes.css
│ │ │ │ ├── fontello-ie7-codes.css
│ │ │ │ └── fontello-ie7.css
│ │ │ ├── demo.html
│ │ │ └── font
│ │ │ │ ├── fontello.eot
│ │ │ │ ├── fontello.svg
│ │ │ │ ├── fontello.ttf
│ │ │ │ └── fontello.woff
│ │ │ ├── images
│ │ │ ├── brandmark.png
│ │ │ └── logo.png
│ │ │ └── slides.css
│ ├── sortable
│ │ ├── _sortable.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── sortable.js
│ │ └── sortable.test.js
│ ├── stacks
│ │ ├── _stacks.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── stacks.js
│ │ └── stacks.test.js
│ ├── subform
│ │ ├── documentation.md
│ │ ├── form-response.html
│ │ ├── index.html
│ │ ├── pattern-test-response.html
│ │ ├── subform-other-response.html
│ │ ├── subform-response.html
│ │ ├── subform.js
│ │ └── subform.test.js
│ ├── switch
│ │ ├── _switch.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── switch.js
│ │ └── switch.test.js
│ ├── syntax-highlight
│ │ ├── _syntax-highlight.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── syntax-highlight.js
│ │ └── syntax-highlight.test.js
│ ├── tabs
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── tabs.js
│ │ ├── tabs.scss
│ │ └── tabs.test.js
│ ├── toggle
│ │ ├── _toggle.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── toggle.js
│ │ └── toggle.test.js
│ ├── tooltip
│ │ ├── _tooltip.scss
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── pattern-test-response.html
│ │ ├── tooltip.js
│ │ └── tooltip.test.js
│ ├── validation
│ │ ├── documentation.md
│ │ ├── index.html
│ │ ├── validation.js
│ │ └── validation.test.js
│ └── zoom
│ │ ├── documentation.md
│ │ ├── images
│ │ ├── slide.002.jpg
│ │ ├── slide.003.jpg
│ │ ├── slide.018.jpg
│ │ ├── slide.019.jpg
│ │ └── slide.032.jpg
│ │ ├── index.html
│ │ ├── zoom.js
│ │ └── zoom.test.js
├── patterns.js
└── setup-tests.js
├── style
├── common.css
├── fontello
│ ├── LICENSE.txt
│ ├── README.txt
│ ├── config.json
│ ├── css
│ │ ├── animation.css
│ │ ├── fontello-codes.css
│ │ ├── fontello-embedded.css
│ │ ├── fontello-ie7-codes.css
│ │ ├── fontello-ie7.css
│ │ └── fontello.css
│ ├── demo.html
│ └── font
│ │ ├── fontello.eot
│ │ ├── fontello.svg
│ │ ├── fontello.ttf
│ │ └── fontello.woff
├── fonts
│ ├── Source_Sans_Pro_300.eot
│ ├── Source_Sans_Pro_300.svg
│ ├── Source_Sans_Pro_300.ttf
│ ├── Source_Sans_Pro_300.woff
│ ├── Source_Sans_Pro_400.eot
│ ├── Source_Sans_Pro_400.svg
│ ├── Source_Sans_Pro_400.ttf
│ ├── Source_Sans_Pro_400.woff
│ ├── Source_Sans_Pro_700.eot
│ ├── Source_Sans_Pro_700.svg
│ ├── Source_Sans_Pro_700.ttf
│ ├── Source_Sans_Pro_700.woff
│ ├── font.css
│ └── patticons
│ │ ├── patticons.otf
│ │ ├── patticons.svg
│ │ ├── patticons.ttf
│ │ └── patticons.woff
├── pattern-icons.svg
├── patterns.css
└── select2x2.png
├── webpack
├── module_federation--dynamic-federation.js
├── module_federation--getOrLoadRemote.js
├── module_federation.js
└── webpack.config.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | end_of_line = lf
4 | indent_style = space
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 |
8 | [*{js,jsx,vue,ts,json}]
9 | indent_size = 4
10 |
11 | [*.{css,scss,xml,html,yml}]
12 | indent_size = 2
13 |
14 | [Makefile]
15 | indent_style = tab
16 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | CHANGES.md merge=union
2 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | branches:
8 | - master
9 | jobs:
10 | build:
11 | name: test
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: actions/setup-node@v4
16 | with:
17 | node-version: '22'
18 | cache: 'yarn'
19 | - run: |
20 | make install
21 | make check
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.css.map
2 | *.log
3 | *.swo
4 | *.swp
5 | *~
6 | .env
7 | .DS_Store
8 | .bundle
9 | .sass-cache
10 | /paternslib.sublime-project
11 | /paternslib.sublime-workspace
12 | /stamp-yarn
13 | Gemfile.lock
14 | Patterns-site/
15 | cache/
16 | coverage/
17 | dist/
18 | node_modules/
19 | src/pat/**/*.css
20 | stats.html
21 | stats.json
22 | test-reports
23 | webpack/cache/
24 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | cache/
2 | coverage/
3 | dist/
4 | node_modules/
5 | stats.json
6 | style/
7 |
--------------------------------------------------------------------------------
/.release-it.js:
--------------------------------------------------------------------------------
1 | const config = require("@patternslib/dev/.release-it.js");
2 |
3 | config.plugins["@release-it/conventional-changelog"].header =
4 | "# Changelog\n\nSee the [history](./docs/history/index.md) for older changelog entries.\n\n";
5 |
6 | module.exports = config;
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | ## Reporting problems
4 |
5 | If you find a bug in Patterns please report to it us. Doing so is very simple:
6 |
7 | - Make sure you have a [GitHub account](https://github.com/signup/free).
8 | - [Submit a ticket for your
9 | issue](https://github.com/Patternslib/Patterns/issues/new), assuming one does
10 | not already exist. Make sure to clearly describe the issue, including steps
11 | to reproduce when it is a bug.
12 | - If possible include a small test case demonstrating the problem. This can either
13 | be provided in the ticket itself, or through a pointer to a
14 | [JSFiddle](http://jsfiddle.net/).
15 |
16 | ## Contributing code
17 |
18 | All code contributions are extremely welcome. In order to contribute please make
19 | sure you have do the following:
20 |
21 | - Read our [code style guide](docs/developer/styleguide.md).
22 | - Make sure you have a [GitHub account](https://github.com/signup/free).
23 | - Create a topic branch from where you want to base your work.
24 | - Make sure _all_ tests are passing before you commit your changes. Use the `make check` command to do this.
25 | - Submit a pull request.
26 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) The Regents of the University of California.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met:
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | 2. Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | 3. Neither the name of the University nor the names of its contributors
13 | may be used to endorse or promote products derived from this software
14 | without specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 | SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ##############
2 | ## Please note
3 | ##############
4 |
5 | # First, run ``make install``.
6 | # After that you have through Makefile extension all the other base targets available.
7 |
8 | # If you want to release on GitHub, make sure to have a .env file with a GITHUB_TOKEN.
9 | # Also see:
10 | # https://github.com/settings/tokens
11 | # and https://github.com/release-it/release-it/blob/master/docs/github-releases.md#automated
12 |
13 |
14 | # Include base Makefile
15 | -include node_modules/@patternslib/dev/Makefile
16 |
17 | # Define the GITHUB_TOKEN in the .env file for usage with release-it.
18 | -include .env
19 | export
20 |
21 | PEGJS ?= npx pegjs
22 | SASS ?= npx sass
23 | YARN ?= npx yarn
24 |
25 | PACKAGE_NAME = "patternslib"
26 |
27 | all:: bundle css
28 |
29 |
30 | yarn.lock install:
31 | $(YARN) install
32 |
33 |
34 | .PHONY: watch
35 | watch: install
36 | $(YARN) watch
37 |
38 |
39 | .PHONY: build
40 | build: bundle css
41 |
42 |
43 | .PHONY: depends-parser
44 | depends-parser: install
45 | $(PEGJS) -O size -f es src/lib/depends_parse.pegjs
46 |
47 |
48 | # Unlink any linked dependencies before building a bundle.
49 | bundle-pre:
50 | -$(YARN) unlink @patternslib/dev
51 | -$(YARN) unlink @patternslib/pat-content-mirror
52 | -$(YARN) unlink @patternslib/pat-doclock
53 | -$(YARN) unlink @patternslib/pat-shopping-cart
54 | -$(YARN) unlink @patternslib/pat-sortable-table
55 | -$(YARN) unlink @patternslib/pat-tiptap
56 | -$(YARN) unlink @patternslib/pat-upload
57 | $(YARN) install --force
58 |
59 |
60 | .PHONY: css
61 | css:
62 | @$(SASS) -I style --load-path node_modules/ _sass/_patterns.scss style/patterns.css
63 |
64 |
65 | # Update patterns-site
66 |
67 |
68 | Patterns-site/Makefile:
69 | git clone git@github.com:Patternslib/Patterns-site.git
70 |
71 |
72 | .PHONY: update-patternslib-site
73 | update-patternslib-site: Patterns-site/Makefile
74 | # something
75 | cd Patterns-site && git pull && make update-patternslib && git push
76 |
77 |
78 | # Overrides release + Update https://patternslib.com
79 |
80 |
81 | .PHONY: release-major
82 | release-major:
83 | make LEVEL=major release
84 | make update-patternslib-site
85 |
86 |
87 | .PHONY: release-minor
88 | release-minor:
89 | make LEVEL=minor release
90 | make update-patternslib-site
91 |
92 |
93 | .PHONY: release-patch
94 | release-patch:
95 | make LEVEL=patch release
96 | make update-patternslib-site
97 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | # Making a release
2 |
3 | We are using release-it together with the conventional-changelog plugin for automatic changelog generation.
4 | Automatic changelog generation needs consistent commit messages wich follow th econventional commits format.
5 | A pre-commit hook checks for each commit message to conform to the specs.
6 | See our [code style guide](docs/developer/styleguide.md) for the changelog format.
7 |
8 | Make sure, you have a ``.env`` file with a ``GITHUB_TOKEN=...`` entry.
9 | This is used for the GitHub release which is created along with the npm release by ``make release-major``, ``make release-minor`` or ``make release-patch``.
10 | Also see: https://github.com/settings/tokens and https://github.com/release-it/release-it/blob/master/docs/github-releases.md#automated
11 |
12 | ## Release process
13 |
14 | - Run ``npm login`` to be able to push to the npm registry.
15 | - Run either of ``make release-major`` for major releases (e.g. 4.0.0), ``make release-minor`` for minor releases (e.g. 4.1.0) or ``make release-patch`` for patch releases (e.g. 4.0.1).
16 | This command runs ``make check``, runs ``release-it`` in dry run and if successful in real, generates the changelog, increases the package.json version, does a git tag, releases the package to npm and creates a zip file of the bundle which is published at the GitHub releases page.
17 | - Check: https://www.npmjs.com/package/@patternslib/patternslib
18 | - Check: https://github.com/Patternslib/Patterns/releases
19 |
20 |
--------------------------------------------------------------------------------
/_sass/_fonts.scss:
--------------------------------------------------------------------------------
1 | // Patterns uses font based icons instead of images. Those are generated
2 | // with Fontello.com Make sure the fontello folder is placed in your
3 | // style folder
4 |
5 | @import "../style/fontello/css/fontello.css";
6 |
7 | // Assets
8 | //@import url(http://fonts.googleapis.com/css?family=Sorts+Mill+Goudy:400,400italic);
9 | //@import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700);
10 | // @import url(/style/fonts/font.css);
11 | // @import url(/style/fontello/fontello.css);
12 |
--------------------------------------------------------------------------------
/_sass/_patterns.scss:
--------------------------------------------------------------------------------
1 | // Each pattern comes with a mixin. They may also be included seperately
2 | // in a project and applied on custom markup.
3 |
4 | @use "fonts";
5 | @use "settings";
6 | @use "mixins";
7 |
8 | // Individual scss files are imported for each Pattern. These files may
9 | // also be imported seperately in a project, but always require the Patterns
10 | // mixins
11 |
12 | @use "components/avatar";
13 | @use "components/button";
14 | @use "components/button-bar";
15 | @use "components/form";
16 | @use "components/icon";
17 | @use "../src/pat/auto-scale/auto-scale";
18 | @use "../src/pat/auto-suggest/auto-suggest";
19 | @use "../src/pat/carousel/carousel";
20 | @use "../src/pat/checklist/checklist";
21 | @use "../src/pat/collapsible/collapsible";
22 | @use "../src/pat/colour-picker/colour-picker";
23 | @use "../src/pat/date-picker/date-picker";
24 | @use "../src/pat/datetime-picker/datetime-picker";
25 | @use "../src/pat/equaliser/equaliser";
26 | @use "../src/pat/expandable-tree/expandable-tree";
27 | @use "../src/pat/focus/focus";
28 | @use "../src/pat/gallery/gallery";
29 | @use "../src/pat/grid/grid";
30 | @use "../src/pat/image-crop/image-crop";
31 | @use "../src/pat/inject/inject";
32 | @use "../src/pat/inject/injection";
33 | @use "../src/pat/masonry/masonry";
34 | @use "../src/pat/menu/menu";
35 | @use "../src/pat/modal/modal";
36 | @use "../src/pat/notification/notification";
37 | @use "../src/pat/sortable/sortable";
38 | @use "../src/pat/stacks/stacks";
39 | @use "../src/pat/switch/switch";
40 | @use "../src/pat/syntax-highlight/syntax-highlight";
41 | @use "../src/pat/toggle/toggle";
42 | @use "../src/pat/tooltip/tooltip";
43 |
--------------------------------------------------------------------------------
/_sass/_settings.scss:
--------------------------------------------------------------------------------
1 | // Colours
2 | // $felt: #89AA74;
3 | $felt: #565656;
4 |
5 | $colour-accent: #0198e1 !default;
6 | $colour-base: #efefef !default;
7 | $colour-alert: red !default;
8 | $colour-success: green !default;
9 | $colour-notice: #ffffd6 !default;
10 | $colour-warning: orange !default;
11 | $colour-error: red !default;
12 | $colour-info: $colour-notice !default;
13 |
14 | // Font treatment
15 | $base-font-size: 18px;
16 | $base-line-height: 150%;
17 | $font-weight-normal: normal;
18 | $font-weight-bold: bold;
19 |
20 | // Glyphs
21 | $glyph-checkbox: "\e2002";
22 | $glyph-checkbox-active: "\e2003";
23 | $glyph-radio-button: "\e2000";
24 | $glyph-radio-button-active: "\e2001";
25 | $glyph-close: "\e2005";
26 |
27 | // We use these to control various global styles
28 | $body-font-family: "Source Sans Pro", sans-serif;
29 | $body-font-weight: $font-weight-normal;
30 | $body-font-style: normal;
31 |
32 | // Categories
33 | $cat-behavioural: #717dd7;
34 | $cat-fancy-stuff: #bf9230;
35 | $cat-form: #be9ac1;
36 | $cat-layout: #a1ced2;
37 |
38 | // Responsive variables
39 |
40 | $break-small: 768px !default;
41 | $break-large: 769px !default;
42 |
--------------------------------------------------------------------------------
/_sass/components/_avatar.scss:
--------------------------------------------------------------------------------
1 | @use "../mixins";
2 |
3 | .pat-avatar {
4 | @include mixins.pat-avatar();
5 | }
6 |
--------------------------------------------------------------------------------
/_sass/components/_button-bar.scss:
--------------------------------------------------------------------------------
1 | .pat-button-bar {
2 | margin-bottom: 1em;
3 | }
4 |
--------------------------------------------------------------------------------
/_sass/components/_icon.scss:
--------------------------------------------------------------------------------
1 | .iconified {
2 | overflow: hidden;
3 | text-decoration: none;
4 | position: relative;
5 | display: inline-block;
6 | white-space: nowrap;
7 | line-height: 10px;
8 | border-style: none;
9 | background-image: none;
10 | filter: none !important;
11 | outline: none !important;
12 | width: 1.3em;
13 | &:active {
14 | box-shadow: none;
15 | }
16 | &:hover {
17 | text-decoration: none;
18 | }
19 | &:before {
20 | text-indent: 0;
21 | display: inline-block;
22 | margin: 0 10px 0 0;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/_sass/components/_photoswipe.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Patternslib/Patterns/25bb1f7956c00043cadcad84b7ac48885f80a06f/_sass/components/_photoswipe.scss
--------------------------------------------------------------------------------
/_sass/components/_tiny-content.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Patternslib/Patterns/25bb1f7956c00043cadcad84b7ac48885f80a06f/_sass/components/_tiny-content.scss
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("@patternslib/dev/babel.config.js");
2 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("@patternslib/dev/commitlint.config.js");
2 |
--------------------------------------------------------------------------------
/docs/designer/markup-styleguide.md:
--------------------------------------------------------------------------------
1 | # The Markup styleguide
2 |
--------------------------------------------------------------------------------
/docs/designer/tips-and-tricks.md:
--------------------------------------------------------------------------------
1 | # Tips and tricks when using patterns
2 |
3 | ## You can disable patterns by changing the URL
4 |
5 | When working with patterns, it might be useful to selectively disable
6 | certain patterns.
7 |
8 | You can easily do this by adding the `patterns-disable` parameter to the query string
9 | of the URL you are on.
10 |
11 | For example, if you'd like to disable the `toggle` pattern, then add
12 | `?patterns-disable=toggle` to your URLs query string.
13 |
--------------------------------------------------------------------------------
/docs/designer/what-is-patternslib.md:
--------------------------------------------------------------------------------
1 | # What is Patternslib?
2 |
3 | Patternslib is a library of reusable patterns which let you create rich, dynamic and interactive prototypes or websites, without having to know or care about Javascript.
4 |
5 | Instead of writing or integrating Javascript, you simply add special CSS classes and HTML5 data attributes to your HTML.
6 | These classes and `data-` attributes describe and invoke the so-called "interaction patterns" of Patternslib which add rich functionality to your page.
7 |
8 | Patternslib is both a library of reusable interaction patterns as well as a small framework for creating such patterns.
9 |
--------------------------------------------------------------------------------
/docs/developer/usage-recipies.md:
--------------------------------------------------------------------------------
1 | # Using require.js to load your custom pattern
2 |
3 | ## Using the bundle
4 |
5 | If you are using a precompiled bundle with require.js, then the following approach is appropriate:
6 |
7 | You should have an entry point for `require.js` in this example `main.js`. So your html will contain:
8 |
9 | ```
10 |
11 | ```
12 |
13 | In your `main.js`, you should define the `registry` module pointing to the bundle as well as any custom modules.
14 | For the sake of simplicity we assume here that there is only one additional module defined that adds a custom pattern.
15 |
16 | So our `main.js` looks like:
17 |
18 | ```
19 | require.config({
20 | paths: {
21 | registry: 'bundle',
22 | custom: 'custom'
23 | },
24 | });
25 | define(['registry', 'custom'], function (registry, custom) {
26 | console.log(registry);
27 | console.log(custom);
28 | console.log(registry.patterns.custom);
29 | });
30 | ```
31 |
32 | ## Without using the bundle
33 |
34 | Not using the bundle, allows you to select patterns individually and gives you a bit more flexibility.
35 | For this example we will assume that you want only the `ajax` pattern as well as the custom pattern defined in the previous section.
36 |
37 | In this case, you will need to explicitly give the paths to all the modules you need.
38 | In the case of the `ajax` pattern we depend on `jquery`, `jquery.form`, `logging`, `parser`, `utils`, `compat`, `jquery-ext`, `registry`.
39 |
40 | Your `main.js` will look similar to:
41 |
42 | ```
43 | require.config({
44 |
45 | paths: {
46 | jquery: 'jquery',
47 | logging: 'logging',
48 | 'jquery.form': 'jquery.form',
49 |
50 | parser: 'patterns_dir/core/parser',
51 | utils: 'patterns_dir/core/utils',
52 | 'jquery-ext': 'patterns_dir/core/jquery-ext',
53 |
54 | registry: 'patterns_dir/core/registry',
55 | ajax: 'patterns_dir/pat/ajax',
56 |
57 | custom: 'custom'
58 | }
59 | });
60 |
61 | define(['registry', 'ajax', 'custom'], function (registry, ajax, custom) {
62 | console.log(registry);
63 | console.log(ajax);
64 | console.log(custom);
65 | console.log(registry.patterns.custom);
66 | });
67 | ```
68 |
--------------------------------------------------------------------------------
/docs/history/index.md:
--------------------------------------------------------------------------------
1 | # History
2 |
3 | The changelog of previous Patternslib releases.
4 |
5 | - [Changelog of Version 8](8.md)
6 | - [Changelog of Version 7](7.md)
7 | - [Changelog of Version 6](6.md)
8 | - [Changelog of Version 5](5.md)
9 | - [Changelog of Version 4](4.md)
10 | - [Changelog of Version 3](3.md)
11 | - [Changelog of Version 2](2.md)
12 | - [Changelog of Version 1](1.md)
13 |
14 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | const config_eslint = require("@patternslib/dev/eslint.config.js");
2 |
3 | module.exports = [
4 | ...config_eslint,
5 | {
6 | ignores: [
7 | // Ignore auto-generated depends_parse.js file.
8 | "src/lib/depends_parse.js",
9 | ],
10 | },
11 | ]
12 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const config = require("@patternslib/dev/jest.config.js");
3 |
4 | config.setupFilesAfterEnv.push(path.resolve(__dirname, "./src/setup-tests.js"));
5 | config.moduleNameMapper["@patternslib/patternslib/(.*)"] =
6 | path.resolve(__dirname) + "/$1";
7 |
8 | module.exports = config;
9 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = require("@patternslib/dev/prettier.config.js");
2 |
--------------------------------------------------------------------------------
/src/core/basepattern.md:
--------------------------------------------------------------------------------
1 | # BasePattern base pattern class.
2 |
3 | A Base pattern for creating scoped patterns.
4 |
5 | Each instance of a pattern has its own local scope.
6 | A new instance is created for each DOM element on which a pattern applies.
7 |
8 |
9 | ## Usage:
10 |
11 | Also see: https://github.com/Patternslib/pat-PATTERN_TEMPLATE
12 |
13 |
14 | import { BasePattern } from "@patternslib/patternslib/src/core/basepattern";
15 | import Parser from "@patternslib/patternslib/src/core/parser";
16 | import registry from "@patternslib/patternslib/src/core/registry";
17 |
18 | export const parser = new Parser("test-pattern");
19 | parser.addArgument("example-option", "Stranger");
20 |
21 | class Pattern extends BasePattern {
22 | static name = "test-pattern";
23 | static trigger = ".pat-test-pattern";
24 | static parser = parser;
25 |
26 | async init() {
27 | import("./test-pattern.scss");
28 |
29 | // Try to avoid jQuery, but here is how to import it.
30 | // eslint-disable-next-line no-unused-vars
31 | const $ = (await import("jquery")).default;
32 |
33 | // The options are automatically created, if parser is defined.
34 | const example_option = this.options.exampleOption;
35 | this.el.innerHTML = `
36 |
hello, ${example_option}, this is pattern ${this.name} speaking.
37 | `;
38 | }
39 | }
40 |
41 | // Register Pattern class in the global pattern registry
42 | registry.register(Pattern);
43 |
44 | // Make it available
45 | export default Pattern;
46 |
47 |
--------------------------------------------------------------------------------
/src/core/feature-detection.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | // Add JavaScript feature as class to the element, just like
3 | // Modernizr does. This is needed for accessibility reasons, to support
4 | // browsers and situations where JavaScript is not available or disabled.
5 | // The HTML root tag needs to have the `no-js` class set which is then
6 | // replaced by `js`.
7 | const html = document.getElementsByTagName("html")[0];
8 | if (html.classList.contains("no-js")) {
9 | html.classList.remove("no-js");
10 | html.classList.add("js");
11 | }
12 |
13 | // NOTE: Modernizr will be removed in an upcoming minor release.
14 |
15 | // Do not load modernizr if disabled. It's enabled by default.
16 | // You might want to disable it for your project by setting:
17 | // window.__patternslib_disable_modernizr = true;
18 | if (window.__patternslib_disable_modernizr) {
19 | return;
20 | }
21 |
22 | // Get the current script tag's URL.
23 | const script_url = document.currentScript.src;
24 | // Get the base URL of the current script tag's URL.
25 | let base_url = script_url.substring(0, script_url.lastIndexOf("/")) + "/";
26 | // The modernizr script is located outside the chunks directory.
27 | base_url = base_url.replace("chunks/", "");
28 |
29 | // Inject a new one with the modernizr bundle.
30 | const script_tag = document.createElement("script");
31 | script_tag.src = base_url + "modernizr.min.js";
32 | document.getElementsByTagName("head")[0].appendChild(script_tag);
33 | })();
34 |
--------------------------------------------------------------------------------
/src/core/feature-detection.md:
--------------------------------------------------------------------------------
1 | # Feature detection
2 |
3 | This module adds the `js` class to the HTML root node and loads Modernizr for more feature detection.
4 |
5 | ---
6 | ** Note **
7 |
8 | If you create own bundles based on Patternslib, you would need to import the `src/core/feature-detection` module for these features to be available.
9 |
10 | ---
11 |
12 |
13 | ## Adding the "js" class for accessibility styles
14 |
15 | There are situations where web browsers do not have JavaScript available or when it is disabled.
16 | In situations where no JavaScript is available you might want to show certain elements where in JavaScript situations you might want to hide them until a JavaScript functionality is showing them.
17 |
18 | In the Media Query Level 5 specification there is a CSS media feature to detect JavaScript via a [`scripting` at-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/scripting).
19 | But at time of this writing this is [not available in any of the major browsers](https://caniuse.com/mdn-css_at-rules_media_scripting).
20 |
21 | Therefore Patternslib adds a `js` class to the HTML root node, if the HTML root node already has a `no-js` class.
22 | The `js` class is set very early before any browser layout is done if you include the Patternslib script in the HEAD of your site.
23 |
24 | Markup:
25 |
26 | ```
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | ```
35 |
36 | When the JavaScript is loaded, the `no-js` class is removed and the `js` class is set:
37 |
38 | ```
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | ```
47 |
48 |
49 | ## Loading Modernizr
50 |
51 | Modernizr is loaded for more feature detection.
52 |
53 | To disable Modernizr you can set `window.__patternslib_disable_modernizr = true;` just before you load the Patternslib bundle:
54 |
55 | ```
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | ```
65 |
66 | ---
67 | ** Note **
68 |
69 | The Modernizr feature detection is being phased out and might be removed in a future version of Patternslib.
70 |
71 | ---
72 |
--------------------------------------------------------------------------------
/src/core/i18n.js:
--------------------------------------------------------------------------------
1 | /* This is a stub, used by patterns that need compatibility with Mockup which
2 | * have i18n support.
3 | *
4 | * Eventually we might want to implement our own i18n functionality here (while
5 | * keeping compatibility with Mockup).
6 | *
7 | * Jed.js would be a good candidate. (http://slexaxton.github.io/Jed)
8 | */
9 |
10 | export default function translate(str) {
11 | return str;
12 | }
13 |
--------------------------------------------------------------------------------
/src/core/jquery-ext.test.js:
--------------------------------------------------------------------------------
1 | import "./jquery-ext";
2 | import $ from "jquery";
3 |
4 | describe("Find including top-level elements", function () {
5 | it("Top-level elements are included", function () {
6 | var $col = $(
7 | "
" +
8 | "" +
9 | "" +
10 | "
" +
11 | "" +
12 | ""
13 | ),
14 | $match = $col.findInclusive("div p");
15 | expect($match.length).toBe(1);
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/src/core/mockup-parser.js:
--------------------------------------------------------------------------------
1 | import $ from "jquery";
2 |
3 | var parser = {
4 | getOptions($el, patternName, options) {
5 | /* This is the Mockup parser. An alternative parser for Patternslib
6 | * patterns.
7 | *
8 | * NOTE: Use of the Mockup parser is discouraged and is added here for
9 | * legacy support for the Plone Mockup project.
10 | *
11 | * It parses a DOM element for pattern configuration options.
12 | */
13 | options = options || {};
14 | // get options from parent element first, stop if element tag name is 'body'
15 | if ($el.length !== 0 && !$.nodeName($el[0], "body")) {
16 | options = this.getOptions($el.parent(), patternName, options);
17 | }
18 | // collect all options from element
19 | let elOptions = {};
20 | if ($el.length !== 0) {
21 | elOptions = $el.data("pat-" + patternName);
22 | if (elOptions) {
23 | // parse options if string
24 | if (typeof elOptions === "string") {
25 | const tmpOptions = {};
26 | $.each(elOptions.split(";"), function (i, item) {
27 | item = item.split(":");
28 | item.reverse();
29 | let key = item.pop();
30 | key = key.replace(/^\s+|\s+$/g, ""); // trim
31 | item.reverse();
32 | let value = item.join(":");
33 | value = value.replace(/^\s+|\s+$/g, ""); // trim
34 | tmpOptions[key] = value;
35 | });
36 | elOptions = tmpOptions;
37 | }
38 | }
39 | }
40 | return $.extend(true, {}, options, elOptions);
41 | },
42 | };
43 |
44 | export default parser;
45 |
--------------------------------------------------------------------------------
/src/core/polyfills.test.js:
--------------------------------------------------------------------------------
1 | import "./polyfills";
2 |
3 | describe("NavigateEvent tests", () => {
4 | afterEach(() => {
5 | document.body.innerHTML = "";
6 | });
7 |
8 | it("should fire an event when history.pushState is called.", () => {
9 | let destination_url;
10 |
11 | window.navigation.addEventListener("navigate", (event) => {
12 | destination_url = event.destination.url;
13 | });
14 |
15 | const path = "foo/bar/baz.html";
16 | history.pushState(null, "", path);
17 |
18 | expect(destination_url).toBe(path);
19 | });
20 |
21 |
22 | it("should fire an event when history.replaceState is called.", () => {
23 | let destination_url;
24 |
25 | window.navigation.addEventListener("navigate", (event) => {
26 | destination_url = event.destination.url;
27 | });
28 |
29 | const path = "foo/bar/baz.html";
30 | history.replaceState(null, "", path);
31 |
32 | expect(destination_url).toBe(path);
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/src/core/remove.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Patterns remove - send event when objects are removed from the DOM
3 | *
4 | * Copyright 2012 Simplon B.V. - Wichert Akkerman
5 | */
6 | import $ from "jquery";
7 |
8 | var real_cleanData = $.cleanData;
9 |
10 | $.cleanData = function remove_cleanData(elems) {
11 | var i, el;
12 | for (i = 0; (el = elems[i]) !== undefined; i++) $(el).triggerHandler("destroy");
13 | real_cleanData.call(this, arguments);
14 | };
15 |
--------------------------------------------------------------------------------
/src/core/url.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Patterns URL - URL parsing utilities
3 | *
4 | * Copyright 2013 Simplon B.V.
5 | */
6 |
7 | function UrlArgumentParser() {
8 | this._cache = null;
9 | if (window.addEventListener) window.addEventListener("popstate", this._reset);
10 | }
11 |
12 | UrlArgumentParser.prototype = {
13 | space_pattern: /\+/g,
14 | keyvalue_pattern: /^(.+?)(?:=(.*))/,
15 |
16 | _reset: function UrlArgumentParser_reset() {
17 | this._cache = null;
18 | },
19 |
20 | _decodeQS: function UrlArgumentParser_decodeQS(bit) {
21 | return decodeURIComponent(bit.replace(this.space_pattern, " "));
22 | },
23 |
24 | _parse: function UrlArgumentParser_parse(qs) {
25 | var query = /\?(.+)/.exec(qs),
26 | params = {};
27 |
28 | if (query === null) return params;
29 |
30 | var parameters = query[1].split("&"),
31 | i,
32 | parts,
33 | key,
34 | value;
35 |
36 | for (i = 0; i < parameters.length; i++) {
37 | if ((parts = this.keyvalue_pattern.exec(parameters[i])) === null) {
38 | key = this._decodeQS(parameters[i]);
39 | value = null;
40 | } else {
41 | key = this._decodeQS(parts[1]);
42 | value = this._decodeQS(parts[2]);
43 | }
44 |
45 | if (params[key] === undefined) params[key] = [];
46 | params[key].push(value);
47 | }
48 |
49 | return params;
50 | },
51 |
52 | get: function UrlArgumentParser_get() {
53 | if (this._cache === null) this._cache = this._parse(window.location.search);
54 | return this._cache;
55 | },
56 | };
57 |
58 | var url_parser = new UrlArgumentParser();
59 |
60 | export default {
61 | UrlArgumentParser: UrlArgumentParser,
62 | parameters: url_parser.get.bind(url_parser),
63 | };
64 |
--------------------------------------------------------------------------------
/src/core/url.test.js:
--------------------------------------------------------------------------------
1 | import url from "./url";
2 |
3 | describe("Core / url / UrlArgumentParser", function () {
4 | describe("_decodeQS", function () {
5 | it("Basic string", function () {
6 | var parser = new url.UrlArgumentParser();
7 | expect(parser._decodeQS("Foo")).toBe("Foo");
8 | });
9 |
10 | it("String with whitespace", function () {
11 | var parser = new url.UrlArgumentParser();
12 | expect(parser._decodeQS("Aap+Noot+Mies")).toBe("Aap Noot Mies");
13 | });
14 |
15 | it("String with encoded characters", function () {
16 | var parser = new url.UrlArgumentParser();
17 | expect(parser._decodeQS("Jip%26Janneke")).toBe("Jip&Janneke");
18 | });
19 | });
20 |
21 | describe("_parse", function () {
22 | it("No query string", function () {
23 | var parser = new url.UrlArgumentParser();
24 | expect(parser._parse("")).toEqual({});
25 | });
26 |
27 | it("No parameter specified", function () {
28 | var parser = new url.UrlArgumentParser();
29 | expect(parser._parse("?")).toEqual({});
30 | });
31 |
32 | it("Parameter without value", function () {
33 | var parser = new url.UrlArgumentParser();
34 | expect(parser._parse("?key")).toEqual({ key: [null] });
35 | });
36 |
37 | it("Parameter with empty value", function () {
38 | var parser = new url.UrlArgumentParser();
39 | expect(parser._parse("?key=")).toEqual({ key: [""] });
40 | });
41 |
42 | it("Parameter with plain value", function () {
43 | var parser = new url.UrlArgumentParser();
44 | expect(parser._parse("?key=value")).toEqual({ key: ["value"] });
45 | });
46 |
47 | it("Multiple parameters", function () {
48 | var parser = new url.UrlArgumentParser();
49 | expect(parser._parse("?one=en&two=to")).toEqual({
50 | one: ["en"],
51 | two: ["to"],
52 | });
53 | });
54 |
55 | it("Parameter with multiple values", function () {
56 | var parser = new url.UrlArgumentParser();
57 | expect(parser._parse("?key=value&key=other")).toEqual({
58 | key: ["value", "other"],
59 | });
60 | });
61 | });
62 | });
63 |
64 | describe("Core / url / parameters", function () {
65 | it("Bound to working parser", function () {
66 | expect(url.parameters()).not.toBe(undefined);
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/src/core/uuid.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Get a universally unique id (uuid).
3 | *
4 | * @returns {String} - The uuid.
5 | */
6 | const create_uuid = () => {
7 | let uuid;
8 | if (window.crypto.randomUUID) {
9 | // Create a real UUID
10 | // window.crypto.randomUUID does only exist in browsers with secure
11 | // context.
12 | // See: https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID
13 | uuid = window.crypto.randomUUID();
14 | } else {
15 | // Create a sufficiently unique ID
16 | const array = new Uint32Array(4);
17 | uuid = window.crypto.getRandomValues(array).join("");
18 | }
19 | return uuid;
20 | };
21 | export default create_uuid;
22 |
--------------------------------------------------------------------------------
/src/core/uuid.test.js:
--------------------------------------------------------------------------------
1 | import create_uuid from "./uuid";
2 |
3 | describe("uuid", function () {
4 | it("returns a UUIDv4", function () {
5 | const uuid = create_uuid();
6 | expect(uuid).toMatch(
7 | /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/
8 | );
9 | });
10 |
11 | it("returns a sufficiently unique id", function () {
12 | // Mock window.crypto.randomUUID not existing, like in browser with
13 | // non-secure context.
14 | const orig_randomUUID = window.crypto.randomUUID;
15 | window.crypto.randomUUID = undefined;
16 |
17 | const uuid = create_uuid();
18 | expect(uuid).toMatch(/^[0-9]*$/);
19 |
20 | window.crypto.randomUUID = orig_randomUUID;
21 | });
22 |
23 | it("the uuid is unique", function () {
24 | expect(create_uuid()).not.toBe(create_uuid());
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // Load modernizr and the `html.js` feature class.
2 | // NOTE: Modernizr will be removed in an upcoming minor release.
3 | import "./core/feature-detection";
4 |
5 | // Webpack entry point for module federation.
6 | import "@patternslib/dev/webpack/module_federation";
7 |
8 | // The next import needs to be kept with parentheses, otherwise we get this error:
9 | // "Shared module is not available for eager consumption."
10 | import("./patterns");
11 |
12 | // Register jQuery gloablly as soon as this script is executed.
13 | async function register_global_libraries() {
14 | const jquery = (await import("jquery")).default;
15 | window.jQuery = jquery;
16 | window.$ = jquery;
17 | }
18 | register_global_libraries();
19 |
--------------------------------------------------------------------------------
/src/pat/auto-scale/_auto-scale.scss:
--------------------------------------------------------------------------------
1 | .pat-auto-scale {
2 | -moz-transform-origin: left top;
3 | -webkit-transform-origin: left top;
4 | transform-origin: left top;
5 | opacity: 0;
6 | -moz-transition: opacity 0.2s;
7 | -webkit-transition: opacity 0.2s;
8 | transition: opacity 0.2s;
9 | }
10 |
11 | .pat-auto-scale.scaled {
12 | opacity: 1;
13 | }
14 |
--------------------------------------------------------------------------------
/src/pat/auto-submit/pattern-test-response.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Feedback
5 |
6 |
7 |
8 |
Succeeded!!
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/pat/auto-submit/placeholder.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Patternslib/Patterns/25bb1f7956c00043cadcad84b7ac48885f80a06f/src/pat/auto-submit/placeholder.gif
--------------------------------------------------------------------------------
/src/pat/auto-suggest/data.json:
--------------------------------------------------------------------------------
1 | [
2 | { "id": "john-snow", "text": "John Snow" },
3 | { "id": "tywin-lannister", "text": "Tywin Lannister" },
4 | { "id": "mary-rose", "text": "Mary Rose" },
5 | { "id": "joe-black", "text": "Joe Black" }
6 | ]
7 |
--------------------------------------------------------------------------------
/src/pat/auto-suggest/datagroup.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "text": "Fruits",
4 | "children": [
5 | {
6 | "id": 1,
7 | "text": "Apples"
8 | },
9 | {
10 | "id": 2,
11 | "text": "Pears"
12 | }
13 | ]
14 | },
15 | {
16 | "text": "Vegetables",
17 | "children": [
18 | {
19 | "id": 3,
20 | "text": "Salad"
21 | },
22 | {
23 | "id": 4,
24 | "text": "Onion"
25 | }
26 | ]
27 | }
28 | ]
29 |
--------------------------------------------------------------------------------
/src/pat/auto-suggest/select2-spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Patternslib/Patterns/25bb1f7956c00043cadcad84b7ac48885f80a06f/src/pat/auto-suggest/select2-spinner.gif
--------------------------------------------------------------------------------
/src/pat/auto-suggest/select2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Patternslib/Patterns/25bb1f7956c00043cadcad84b7ac48885f80a06f/src/pat/auto-suggest/select2.png
--------------------------------------------------------------------------------
/src/pat/auto-suggest/select2x2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Patternslib/Patterns/25bb1f7956c00043cadcad84b7ac48885f80a06f/src/pat/auto-suggest/select2x2.png
--------------------------------------------------------------------------------
/src/pat/autofocus/autofocus.js:
--------------------------------------------------------------------------------
1 | import $ from "jquery";
2 | import { BasePattern } from "../../core/basepattern";
3 | import dom from "../../core/dom";
4 | import registry from "../../core/registry";
5 |
6 | let scheduled_task = null;
7 |
8 | class Pattern extends BasePattern {
9 | static name = "autofocus";
10 | static trigger = `
11 | input.pat-autofocus,
12 | input[autofocus],
13 | select.pat-autofocus,
14 | select[autofocus],
15 | textarea.pat-autofocus,
16 | textarea[autofocus],
17 | button.pat-autofocus,
18 | button[autofocus]
19 | `;
20 |
21 | init() {
22 | if (window.self !== window.top) {
23 | // Do not autofocus in iframes.
24 | return;
25 | }
26 |
27 | // Re-focus after relevant DOM changes.
28 | $(document).on("pat-update", (e, data) => {
29 | const updated = data?.dom;
30 | if (updated?.contains(this.el)) {
31 | // Only focus if the updated element is a parent of this autofocus element.
32 | this.set_focus();
33 | }
34 | });
35 |
36 | this.set_focus();
37 | }
38 |
39 | set_focus() {
40 | if (dom.is_visible(this.el) && this.el.value === "") {
41 | // Set autofocus only for visible and empty inputs.
42 |
43 | // Clear scheduled tasks if there are any.
44 | // Note: Patterns scanning initizlizes patterns "inside-out", so
45 | // DOM nodes later in the tree are initizlized first.
46 | // With multiple pattern instantiations and then module-
47 | // globally clearing and re-scheduling tasks we are
48 | // initializing in the end the first pattern which matches
49 | // the conditions.
50 | clearTimeout(scheduled_task);
51 | scheduled_task = setTimeout(() => {
52 | this.el.focus();
53 | scheduled_task = null;
54 | }, 100);
55 | }
56 | }
57 | }
58 |
59 | registry.register(Pattern);
60 |
61 | export default Pattern;
62 | export { Pattern };
63 |
--------------------------------------------------------------------------------
/src/pat/autofocus/documentation.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | With the Autofocus pattern you may choose which input field gets the focus when a page is loaded or injected.
4 |
5 |
6 | ## Documentation
7 |
8 | Patterns augments the standard HTML5 autofocus behaviour.
9 |
10 | On initial page load or when new content is injected it is scanned for input elements with an `autofocus` attribute or `pat-autofocus` class.
11 |
12 | The first such element that has no current value will be given the focus.
13 |
14 |
18 |
19 | In this example the keywords input field would be given the focus since the title field already has a value.
20 |
--------------------------------------------------------------------------------
/src/pat/autofocus/index-iframed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | pat-autofocus iframe'd demo page
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/pat/autofocus/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | pat-autofocus demo page
5 |
6 |
7 |
8 |
9 |
10 |
47 |
48 |
Elements in the iframe below should not get the focus.
` structure as plain text.
9 |
10 | This pattern is especially useful when writing interactive documentation and showing the code at the same time.
11 |
12 |
13 | ### Usage
14 |
15 | This pattern is enabled by adding the `pat-clone` class on a container element which contains the original element and any clones of it that may have beeen added.
16 | The first element inside the .pat-clone container is by default assumed to be the original element may be cloned by the user.
17 |
18 |
19 |
Hello.
20 |
21 |
22 | This will result in:
23 |
24 |
25 |
26 | <p>Hello.</p>
27 |
28 |
29 |
30 |
31 | ### Excluding markup from copying
32 |
33 | You can exclude markup from copying by adding the `clone-code` class to it.
34 | If that class is present, the whole `clone-code` markup subtree is ignored.
35 |
36 |
37 | ### Option reference
38 |
39 | | Property | Description | Default | Type |
40 | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------- | --------------------------------- |
41 | | source | CSS selector to define the source from where the markup should be copied. | :first-child | CSS Selector |
42 | | features | List of features to activate. Currently only `format` is implemented. Format does prettify the HTML markup with the library `prettier`. | null | Comma seperated list of strings. |
43 |
44 |
--------------------------------------------------------------------------------
/src/pat/clone-code/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | pat-clone demo page
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
Clone Code
13 |
14 |
Example 1
15 |
16 |
17 | Clone the next block and ignore this paragraph which has the `clone-ignore` class.
18 |
19 |
20 |
21 |
Hello.
22 |
23 |
24 |
Example 2
25 |
26 |
27 | Clone the whole HTML page but ignore this paragraph which has the `clone-ignore` class.
28 |
29 |
30 |
32 |
Test paragraph
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/pat/close-panel/close-panel.js:
--------------------------------------------------------------------------------
1 | import Base from "../../core/base";
2 | import events from "../../core/events";
3 | import utils from "../../core/utils";
4 |
5 | export default Base.extend({
6 | name: "close-panel",
7 | trigger: ".close-panel",
8 |
9 | init() {
10 | // Close panel support for dialog panels
11 | // Other modals are handled in pat-modal.
12 | const dialog_panel = this.el.closest("dialog");
13 | if (dialog_panel) {
14 | events.add_event_listener(
15 | dialog_panel,
16 | "close-panel",
17 | "close-panel--dialog",
18 | () => {
19 | dialog_panel.close();
20 | }
21 | );
22 | }
23 |
24 | this.el.addEventListener("click", async (e) => {
25 | await utils.timeout(0); // Wait for other patterns, like pat-validation.
26 |
27 | if (
28 | e.target.matches(":not([formnovalidate])") &&
29 | e.target.matches("[type=submit], button:not([type=button])") &&
30 | this.el.closest("form")?.checkValidity() === false
31 | ) {
32 | // Prevent closing an invalid form when submitting.
33 | return;
34 | }
35 |
36 | this.el.dispatchEvent(
37 | new Event("close-panel", { bubbles: true, cancelable: true })
38 | );
39 | });
40 | },
41 | });
42 |
--------------------------------------------------------------------------------
/src/pat/close-panel/documentation.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | Closes a previously opened panels when clicking on elements with a ``close-panel`` class on it.
4 |
5 | The element with the ``close-panel`` class must be a child element of the panel which should be closed.
6 |
7 | This pattern works together with:
8 |
9 | - panels which are ``