├── dev
├── assets
│ ├── map.png
│ ├── avatar.png
│ ├── donuts.png
│ ├── quasar.jpg
│ ├── boy-avatar.png
│ ├── guy-avatar.png
│ ├── mountains.jpg
│ ├── parallax1.jpg
│ ├── parallax2.jpg
│ └── linux-avatar.png
├── statics
│ ├── map.png
│ ├── quasar.jpg
│ ├── boy-avatar.png
│ ├── guy-avatar.png
│ ├── mountains.jpg
│ ├── parallax1.jpg
│ ├── parallax2.jpg
│ ├── linux-avatar.png
│ ├── quasar-logo.png
│ └── linux-avatar-2.png
├── components
│ ├── css
│ │ ├── flex-addon.styl
│ │ ├── shadows.vue
│ │ ├── flex-test.vue
│ │ └── material-ripples.vue
│ ├── web-tests
│ │ ├── c.vue
│ │ ├── b.vue
│ │ ├── a.vue
│ │ ├── fast-test.vue
│ │ └── breakpoints.vue
│ ├── components
│ │ ├── video-embedding.vue
│ │ ├── back-to-top.vue
│ │ ├── scroll-area.vue
│ │ ├── scroll-fire.vue
│ │ ├── infinite-scroll.vue
│ │ ├── popover-test.vue
│ │ └── no-ssr.vue
│ ├── touch-directives
│ │ ├── touch-style.styl
│ │ └── touch-hold.vue
│ ├── other
│ │ ├── screen-plugin.vue
│ │ ├── platform-detection.vue
│ │ ├── app-visibility.vue
│ │ ├── vue-transitions.vue
│ │ ├── app-fullscreen.vue
│ │ ├── cookies.vue
│ │ └── close-overlay.vue
│ ├── meta
│ │ ├── layout_2.vue
│ │ ├── layout_1.vue
│ │ └── pages
│ │ │ ├── third.vue
│ │ │ └── second.vue
│ ├── new-layout
│ │ └── pages
│ │ │ ├── b.vue
│ │ │ └── c.vue
│ ├── index.vue
│ └── form
│ │ └── rating.vue
├── app.styl
├── pages.js
├── app.entry-client.js
├── spa.index.html
├── ssr.index.html
├── app.entry-server.js
└── app.js
├── src
├── components
│ ├── alert
│ │ ├── index.js
│ │ ├── alert.ios.styl
│ │ └── alert.mat.styl
│ ├── chip
│ │ └── index.js
│ ├── field
│ │ └── index.js
│ ├── icon
│ │ ├── index.js
│ │ └── QIcon.js
│ ├── input
│ │ ├── index.js
│ │ └── input-types.js
│ ├── knob
│ │ ├── index.js
│ │ ├── knob.ios.styl
│ │ └── knob.mat.styl
│ ├── radio
│ │ ├── index.js
│ │ ├── radio.ios.styl
│ │ ├── radio.mat.styl
│ │ └── QRadio.js
│ ├── range
│ │ └── index.js
│ ├── tree
│ │ └── index.js
│ ├── video
│ │ ├── index.js
│ │ ├── video.ios.styl
│ │ ├── video.mat.styl
│ │ └── QVideo.js
│ ├── dialog
│ │ └── index.js
│ ├── editor
│ │ ├── index.js
│ │ ├── editor.ios.styl
│ │ └── editor.mat.styl
│ ├── no-ssr
│ │ ├── index.js
│ │ └── QNoSsr.js
│ ├── rating
│ │ ├── index.js
│ │ ├── rating.ios.styl
│ │ └── rating.mat.styl
│ ├── search
│ │ ├── index.js
│ │ ├── search.ios.styl
│ │ └── search.mat.styl
│ ├── select
│ │ ├── index.js
│ │ ├── select.ios.styl
│ │ └── select.mat.styl
│ ├── slider
│ │ └── index.js
│ ├── toggle
│ │ ├── index.js
│ │ ├── toggle.mat.styl
│ │ ├── toggle.ios.styl
│ │ └── QToggle.js
│ ├── ajax-bar
│ │ ├── index.js
│ │ ├── ajax-bar.ios.styl
│ │ └── ajax-bar.mat.styl
│ ├── popover
│ │ ├── index.js
│ │ ├── popover.ios.styl
│ │ └── popover.mat.styl
│ ├── tooltip
│ │ ├── index.js
│ │ ├── tooltip.mat.styl
│ │ └── tooltip.ios.styl
│ ├── checkbox
│ │ ├── index.js
│ │ ├── checkbox.ios.styl
│ │ └── checkbox.mat.styl
│ ├── parallax
│ │ ├── index.js
│ │ ├── parallax.ios.styl
│ │ └── parallax.mat.styl
│ ├── progress
│ │ └── index.js
│ ├── uploader
│ │ ├── index.js
│ │ ├── uploader.ios.styl
│ │ └── uploader.mat.styl
│ ├── chat
│ │ └── index.js
│ ├── jumbotron
│ │ ├── index.js
│ │ ├── jumbotron.ios.styl
│ │ ├── jumbotron.mat.styl
│ │ └── QJumbotron.js
│ ├── pagination
│ │ ├── index.js
│ │ ├── pagination.ios.styl
│ │ └── pagination.mat.styl
│ ├── popup-edit
│ │ └── index.js
│ ├── action-sheet
│ │ ├── index.js
│ │ ├── action-sheet.mat.styl
│ │ └── action-sheet.ios.styl
│ ├── chips-input
│ │ ├── index.js
│ │ ├── chips-input.ios.styl
│ │ └── chips-input.mat.styl
│ ├── collapsible
│ │ ├── index.js
│ │ ├── collapsible.ios.styl
│ │ └── collapsible.mat.styl
│ ├── context-menu
│ │ └── index.js
│ ├── input-frame
│ │ └── index.js
│ ├── option-group
│ │ ├── index.js
│ │ ├── option-group.mat.styl
│ │ └── option-group.ios.styl
│ ├── scroll-area
│ │ ├── index.js
│ │ ├── scroll-area.ios.styl
│ │ └── scroll-area.mat.styl
│ ├── autocomplete
│ │ ├── index.js
│ │ ├── autocomplete.ios.styl
│ │ └── autocomplete.mat.styl
│ ├── inner-loading
│ │ ├── index.js
│ │ ├── inner-loading.ios.styl
│ │ ├── inner-loading.mat.styl
│ │ └── QInnerLoading.js
│ ├── pull-to-refresh
│ │ ├── index.js
│ │ ├── pull-to-refresh.ios.styl
│ │ └── pull-to-refresh.mat.styl
│ ├── infinite-scroll
│ │ └── index.js
│ ├── table
│ │ ├── table-expand.js
│ │ ├── index.js
│ │ ├── QTr.js
│ │ ├── table-filter.js
│ │ ├── QTd.js
│ │ ├── table-column-selection.js
│ │ ├── QTableColumns.js
│ │ └── QTh.js
│ ├── slide-transition
│ │ ├── index.js
│ │ ├── slide-transition.ios.styl
│ │ └── slide-transition.mat.styl
│ ├── fab
│ │ ├── index.js
│ │ ├── fab-mixin.js
│ │ ├── QFabAction.js
│ │ ├── fab.ios.styl
│ │ └── fab.mat.styl
│ ├── btn
│ │ ├── btn-dropdown.ios.styl
│ │ ├── btn-dropdown.mat.styl
│ │ ├── index.js
│ │ ├── QBtnGroup.js
│ │ ├── btn-group.ios.styl
│ │ └── btn-group.mat.styl
│ ├── spinner
│ │ ├── QSpinner.js
│ │ ├── spinner-mixin.js
│ │ ├── spinner.mat.styl
│ │ ├── spinner.ios.styl
│ │ ├── QSpinner.mat.js
│ │ ├── QSpinnerInfinity.js
│ │ ├── QSpinnerOval.js
│ │ └── index.js
│ ├── color
│ │ └── index.js
│ ├── modal
│ │ └── index.js
│ ├── toolbar
│ │ ├── index.js
│ │ ├── QToolbarTitle.js
│ │ ├── toolbar.mat.styl
│ │ ├── toolbar.ios.styl
│ │ └── QToolbar.js
│ ├── datetime
│ │ ├── index.js
│ │ └── datetime-props.js
│ ├── timeline
│ │ ├── index.js
│ │ └── QTimeline.js
│ ├── breadcrumbs
│ │ ├── index.js
│ │ ├── breadcrumbs.ios.styl
│ │ ├── breadcrumbs.mat.styl
│ │ └── QBreadcrumbsEl.js
│ ├── card
│ │ ├── QCardMain.js
│ │ ├── QCardSeparator.js
│ │ ├── index.js
│ │ ├── QCardTitle.js
│ │ ├── QCardMedia.js
│ │ ├── QCardActions.js
│ │ ├── QCard.js
│ │ ├── card.ios.styl
│ │ └── card.mat.styl
│ ├── stepper
│ │ ├── index.js
│ │ └── QStepperNavigation.js
│ ├── dot
│ │ ├── dot.ios.styl
│ │ └── dot.mat.styl
│ ├── tab
│ │ ├── index.js
│ │ ├── QTab.js
│ │ └── QTabPane.js
│ ├── loading
│ │ ├── loading.ios.styl
│ │ └── loading.mat.styl
│ ├── carousel
│ │ ├── index.js
│ │ ├── QCarouselControl.js
│ │ └── QCarouselSlide.js
│ ├── observables
│ │ ├── index.js
│ │ └── QWindowResizeObservable.js
│ ├── list
│ │ ├── QListHeader.js
│ │ ├── QItemSeparator.js
│ │ ├── index.js
│ │ ├── QItem.js
│ │ ├── QItemMain.js
│ │ └── QList.js
│ └── layout
│ │ ├── index.js
│ │ ├── QPageContainer.js
│ │ └── QPage.js
├── utils
│ ├── clone.js
│ ├── filter.js
│ ├── uid.js
│ ├── throttle.js
│ ├── open-url.js
│ ├── frame-debounce.js
│ ├── sort.js
│ ├── debounce.js
│ ├── escape-key.js
│ ├── is.js
│ ├── router-link.js
│ ├── modal-fn.js
│ ├── format.js
│ ├── animate.js
│ ├── dom.js
│ └── prevent-scroll.js
├── css
│ ├── ios.styl
│ ├── mat.styl
│ ├── core
│ │ ├── touch.styl
│ │ ├── elevation.styl
│ │ ├── orientation.styl
│ │ ├── mouse.styl
│ │ ├── helpers.styl
│ │ ├── ripples.styl
│ │ ├── size.styl
│ │ └── positioning.styl
│ └── critical.styl
├── plugins
│ ├── dialog.js
│ ├── action-sheet.js
│ ├── local-storage.js
│ ├── session-storage.js
│ ├── loading-bar.js
│ ├── app-visibility.js
│ ├── app-fullscreen.js
│ └── addressbar-color.js
├── mixins
│ ├── can-render.js
│ ├── display-mode.js
│ ├── align.js
│ ├── parent-field.js
│ ├── item.js
│ ├── checkbox.js
│ └── fullscreen.js
├── vue-plugin.js
├── index.esm.js
├── icons.js
├── directives.js
├── ssr-update.js
├── index.umd.js
├── directives
│ ├── close-overlay.js
│ ├── go-back.js
│ └── scroll.js
├── utils.js
├── plugins.js
├── history.js
└── i18n.js
├── .bithoundrc
├── .codeclimate.yml
├── .gitignore
├── .postcssrc.js
├── .editorconfig
├── circle.yml
├── jsconfig.json
├── .babelrc
├── .stylintrc
├── LICENSE
├── .github
├── CODE_OF_CONDUCT.md
└── PULL_REQUEST_TEMPLATE.md
└── .eslintrc.js
/dev/assets/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/map.png
--------------------------------------------------------------------------------
/dev/assets/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/avatar.png
--------------------------------------------------------------------------------
/dev/assets/donuts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/donuts.png
--------------------------------------------------------------------------------
/dev/assets/quasar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/quasar.jpg
--------------------------------------------------------------------------------
/dev/statics/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/map.png
--------------------------------------------------------------------------------
/dev/components/css/flex-addon.styl:
--------------------------------------------------------------------------------
1 | @import '~variables'
2 | @import '../../src/css/flex-addon.styl'
3 |
--------------------------------------------------------------------------------
/dev/statics/quasar.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/quasar.jpg
--------------------------------------------------------------------------------
/src/components/alert/index.js:
--------------------------------------------------------------------------------
1 | import QAlert from './QAlert.js'
2 |
3 | export {
4 | QAlert
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/chip/index.js:
--------------------------------------------------------------------------------
1 | import QChip from './QChip.js'
2 |
3 | export {
4 | QChip
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/field/index.js:
--------------------------------------------------------------------------------
1 | import QField from './QField.js'
2 |
3 | export {
4 | QField
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/icon/index.js:
--------------------------------------------------------------------------------
1 | import QIcon from './QIcon.js'
2 |
3 | export {
4 | QIcon
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/input/index.js:
--------------------------------------------------------------------------------
1 | import QInput from './QInput.js'
2 |
3 | export {
4 | QInput
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/knob/index.js:
--------------------------------------------------------------------------------
1 | import QKnob from './QKnob.js'
2 |
3 | export {
4 | QKnob
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/radio/index.js:
--------------------------------------------------------------------------------
1 | import QRadio from './QRadio.js'
2 |
3 | export {
4 | QRadio
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/range/index.js:
--------------------------------------------------------------------------------
1 | import QRange from './QRange.js'
2 |
3 | export {
4 | QRange
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/tree/index.js:
--------------------------------------------------------------------------------
1 | import QTree from './QTree.js'
2 |
3 | export {
4 | QTree
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/video/index.js:
--------------------------------------------------------------------------------
1 | import QVideo from './QVideo.js'
2 |
3 | export {
4 | QVideo
5 | }
6 |
--------------------------------------------------------------------------------
/.bithoundrc:
--------------------------------------------------------------------------------
1 | {
2 | "ignore": [
3 | "dist/**",
4 | "test/**",
5 | "dev/**"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/dev/assets/boy-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/boy-avatar.png
--------------------------------------------------------------------------------
/dev/assets/guy-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/guy-avatar.png
--------------------------------------------------------------------------------
/dev/assets/mountains.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/mountains.jpg
--------------------------------------------------------------------------------
/dev/assets/parallax1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/parallax1.jpg
--------------------------------------------------------------------------------
/dev/assets/parallax2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/parallax2.jpg
--------------------------------------------------------------------------------
/dev/statics/boy-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/boy-avatar.png
--------------------------------------------------------------------------------
/dev/statics/guy-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/guy-avatar.png
--------------------------------------------------------------------------------
/dev/statics/mountains.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/mountains.jpg
--------------------------------------------------------------------------------
/dev/statics/parallax1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/parallax1.jpg
--------------------------------------------------------------------------------
/dev/statics/parallax2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/parallax2.jpg
--------------------------------------------------------------------------------
/src/components/dialog/index.js:
--------------------------------------------------------------------------------
1 | import QDialog from './QDialog.js'
2 |
3 | export {
4 | QDialog
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/editor/index.js:
--------------------------------------------------------------------------------
1 | import QEditor from './QEditor.js'
2 |
3 | export {
4 | QEditor
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/no-ssr/index.js:
--------------------------------------------------------------------------------
1 | import QNoSsr from './QNoSsr.js'
2 |
3 | export {
4 | QNoSsr
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/rating/index.js:
--------------------------------------------------------------------------------
1 | import QRating from './QRating.js'
2 |
3 | export {
4 | QRating
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/search/index.js:
--------------------------------------------------------------------------------
1 | import QSearch from './QSearch.js'
2 |
3 | export {
4 | QSearch
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/search/search.ios.styl:
--------------------------------------------------------------------------------
1 | .q-toolbar .q-search
2 | background rgba(255, 255, 255, .25)
3 |
--------------------------------------------------------------------------------
/src/components/search/search.mat.styl:
--------------------------------------------------------------------------------
1 | .q-toolbar .q-search
2 | background rgba(255, 255, 255, .25)
3 |
--------------------------------------------------------------------------------
/src/components/select/index.js:
--------------------------------------------------------------------------------
1 | import QSelect from './QSelect.js'
2 |
3 | export {
4 | QSelect
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/slider/index.js:
--------------------------------------------------------------------------------
1 | import QSlider from './QSlider.js'
2 |
3 | export {
4 | QSlider
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/toggle/index.js:
--------------------------------------------------------------------------------
1 | import QToggle from './QToggle.js'
2 |
3 | export {
4 | QToggle
5 | }
6 |
--------------------------------------------------------------------------------
/dev/assets/linux-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/assets/linux-avatar.png
--------------------------------------------------------------------------------
/dev/statics/linux-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/linux-avatar.png
--------------------------------------------------------------------------------
/dev/statics/quasar-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/quasar-logo.png
--------------------------------------------------------------------------------
/src/components/ajax-bar/index.js:
--------------------------------------------------------------------------------
1 | import QAjaxBar from './QAjaxBar.js'
2 |
3 | export {
4 | QAjaxBar
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/popover/index.js:
--------------------------------------------------------------------------------
1 | import QPopover from './QPopover.js'
2 |
3 | export {
4 | QPopover
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/tooltip/index.js:
--------------------------------------------------------------------------------
1 | import QTooltip from './QTooltip.js'
2 |
3 | export {
4 | QTooltip
5 | }
6 |
--------------------------------------------------------------------------------
/dev/statics/linux-avatar-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Abdelaziz18003/quasar/dev/dev/statics/linux-avatar-2.png
--------------------------------------------------------------------------------
/src/components/checkbox/index.js:
--------------------------------------------------------------------------------
1 | import QCheckbox from './QCheckbox.js'
2 |
3 | export {
4 | QCheckbox
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/parallax/index.js:
--------------------------------------------------------------------------------
1 | import QParallax from './QParallax.js'
2 |
3 | export {
4 | QParallax
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/progress/index.js:
--------------------------------------------------------------------------------
1 | import QProgress from './QProgress.js'
2 |
3 | export {
4 | QProgress
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/uploader/index.js:
--------------------------------------------------------------------------------
1 | import QUploader from './QUploader.js'
2 |
3 | export {
4 | QUploader
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/chat/index.js:
--------------------------------------------------------------------------------
1 | import QChatMessage from './QChatMessage.js'
2 |
3 | export {
4 | QChatMessage
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/jumbotron/index.js:
--------------------------------------------------------------------------------
1 | import QJumbotron from './QJumbotron.js'
2 |
3 | export {
4 | QJumbotron
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/pagination/index.js:
--------------------------------------------------------------------------------
1 | import QPagination from './QPagination.js'
2 |
3 | export {
4 | QPagination
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/popup-edit/index.js:
--------------------------------------------------------------------------------
1 | import QPopupEdit from './QPopupEdit.js'
2 |
3 | export {
4 | QPopupEdit
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/action-sheet/index.js:
--------------------------------------------------------------------------------
1 | import QActionSheet from './QActionSheet.js'
2 |
3 | export {
4 | QActionSheet
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/chips-input/index.js:
--------------------------------------------------------------------------------
1 | import QChipsInput from './QChipsInput.js'
2 |
3 | export {
4 | QChipsInput
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/collapsible/index.js:
--------------------------------------------------------------------------------
1 | import QCollapsible from './QCollapsible.js'
2 |
3 | export {
4 | QCollapsible
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/context-menu/index.js:
--------------------------------------------------------------------------------
1 | import QContextMenu from './QContextMenu.js'
2 |
3 | export {
4 | QContextMenu
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/input-frame/index.js:
--------------------------------------------------------------------------------
1 | import QInputFrame from './QInputFrame.js'
2 |
3 | export {
4 | QInputFrame
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/option-group/index.js:
--------------------------------------------------------------------------------
1 | import QOptionGroup from './QOptionGroup.js'
2 |
3 | export {
4 | QOptionGroup
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/scroll-area/index.js:
--------------------------------------------------------------------------------
1 | import QScrollArea from './QScrollArea.js'
2 |
3 | export {
4 | QScrollArea
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/select/select.ios.styl:
--------------------------------------------------------------------------------
1 | body.desktop .q-select-highlight
2 | background $item-highlight-color !important
3 |
--------------------------------------------------------------------------------
/src/components/select/select.mat.styl:
--------------------------------------------------------------------------------
1 | body.desktop .q-select-highlight
2 | background $item-highlight-color !important
3 |
--------------------------------------------------------------------------------
/src/components/autocomplete/index.js:
--------------------------------------------------------------------------------
1 | import QAutocomplete from './QAutocomplete.js'
2 |
3 | export {
4 | QAutocomplete
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/inner-loading/index.js:
--------------------------------------------------------------------------------
1 | import QInnerLoading from './QInnerLoading.js'
2 |
3 | export {
4 | QInnerLoading
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/autocomplete/autocomplete.ios.styl:
--------------------------------------------------------------------------------
1 | body.desktop .q-select-highlight
2 | background $item-highlight-color !important
3 |
--------------------------------------------------------------------------------
/src/components/autocomplete/autocomplete.mat.styl:
--------------------------------------------------------------------------------
1 | body.desktop .q-select-highlight
2 | background $item-highlight-color !important
3 |
--------------------------------------------------------------------------------
/src/components/pull-to-refresh/index.js:
--------------------------------------------------------------------------------
1 | import QPullToRefresh from './QPullToRefresh.js'
2 |
3 | export {
4 | QPullToRefresh
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/infinite-scroll/index.js:
--------------------------------------------------------------------------------
1 | import QInfiniteScroll from './QInfiniteScroll.js'
2 |
3 | export {
4 | QInfiniteScroll
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/table/table-expand.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data () {
3 | return {
4 | rowsExpanded: {}
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/slide-transition/index.js:
--------------------------------------------------------------------------------
1 | import QSlideTransition from './QSlideTransition.js'
2 |
3 | export {
4 | QSlideTransition
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/slide-transition/slide-transition.ios.styl:
--------------------------------------------------------------------------------
1 | .q-slide-transition
2 | transition height .3s cubic-bezier(.25, .8, .50, 1) !important
3 |
--------------------------------------------------------------------------------
/src/components/slide-transition/slide-transition.mat.styl:
--------------------------------------------------------------------------------
1 | .q-slide-transition
2 | transition height .3s cubic-bezier(.25, .8, .50, 1) !important
3 |
--------------------------------------------------------------------------------
/src/utils/clone.js:
--------------------------------------------------------------------------------
1 | export default function (data) {
2 | const s = JSON.stringify(data)
3 | if (s) {
4 | return JSON.parse(s)
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/dev/app.styl:
--------------------------------------------------------------------------------
1 | .caption
2 | margin 35px 0
3 | padding 12px 0 12px 12px
4 | border-left 4px solid #027be3
5 | font-weight bold
6 | margin-left 10px
7 |
--------------------------------------------------------------------------------
/src/components/fab/index.js:
--------------------------------------------------------------------------------
1 | import QFab from './QFab.js'
2 | import QFabAction from './QFabAction.js'
3 |
4 | export {
5 | QFab,
6 | QFabAction
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/btn/btn-dropdown.ios.styl:
--------------------------------------------------------------------------------
1 | .q-btn-dropdown-split .q-btn-dropdown-arrow
2 | padding 0 4px
3 | border-left 1px solid rgba(255, 255, 255, .3)
4 |
--------------------------------------------------------------------------------
/src/components/btn/btn-dropdown.mat.styl:
--------------------------------------------------------------------------------
1 | .q-btn-dropdown-split .q-btn-dropdown-arrow
2 | padding 0 4px
3 | border-left 1px solid rgba(255, 255, 255, .3)
4 |
--------------------------------------------------------------------------------
/src/components/inner-loading/inner-loading.ios.styl:
--------------------------------------------------------------------------------
1 | .q-inner-loading
2 | background $light-dimmed-background
3 | &.dark
4 | background $dimmed-background
5 |
--------------------------------------------------------------------------------
/src/components/inner-loading/inner-loading.mat.styl:
--------------------------------------------------------------------------------
1 | .q-inner-loading
2 | background $light-dimmed-background
3 | &.dark
4 | background $dimmed-background
5 |
--------------------------------------------------------------------------------
/src/components/spinner/QSpinner.js:
--------------------------------------------------------------------------------
1 | import DefaultSpinner from './QSpinner'
2 |
3 | export default {
4 | mixins: [DefaultSpinner],
5 | name: 'QSpinner'
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/color/index.js:
--------------------------------------------------------------------------------
1 | import QColor from './QColor.js'
2 | import QColorPicker from './QColorPicker.js'
3 |
4 | export {
5 | QColor,
6 | QColorPicker
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/modal/index.js:
--------------------------------------------------------------------------------
1 | import QModal from './QModal.js'
2 | import QModalLayout from './QModalLayout.js'
3 |
4 | export {
5 | QModal,
6 | QModalLayout
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/input/input-types.js:
--------------------------------------------------------------------------------
1 | export default [
2 | 'text', 'textarea', 'email', 'search',
3 | 'tel', 'file', 'number',
4 | 'password', 'url', 'time', 'date'
5 | ]
6 |
--------------------------------------------------------------------------------
/src/components/toolbar/index.js:
--------------------------------------------------------------------------------
1 | import QToolbar from './QToolbar.js'
2 | import QToolbarTitle from './QToolbarTitle.js'
3 |
4 | export {
5 | QToolbar,
6 | QToolbarTitle
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/datetime/index.js:
--------------------------------------------------------------------------------
1 | import QDatetime from './QDatetime.js'
2 | import QDatetimePicker from './QDatetimePicker'
3 |
4 | export {
5 | QDatetime,
6 | QDatetimePicker
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/timeline/index.js:
--------------------------------------------------------------------------------
1 | import QTimeline from './QTimeline.js'
2 | import QTimelineEntry from './QTimelineEntry.js'
3 |
4 | export {
5 | QTimeline,
6 | QTimelineEntry
7 | }
8 |
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | languages:
2 | JavaScript: true
3 | exclude_paths:
4 | - "node_modules/*"
5 | - "dist/*"
6 | - "test/*"
7 | - "src/lib/core/platform/platform.js"
8 | - "preview/*"
9 |
--------------------------------------------------------------------------------
/src/components/checkbox/checkbox.ios.styl:
--------------------------------------------------------------------------------
1 | $checkbox-size = 21px
2 |
3 | .q-checkbox-icon
4 | height $checkbox-size
5 | width $checkbox-size
6 | font-size $checkbox-size
7 | opacity 0
8 |
--------------------------------------------------------------------------------
/src/components/checkbox/checkbox.mat.styl:
--------------------------------------------------------------------------------
1 | $checkbox-size = 21px
2 |
3 | .q-checkbox-icon
4 | height $checkbox-size
5 | width $checkbox-size
6 | font-size $checkbox-size
7 | opacity 0
8 |
--------------------------------------------------------------------------------
/src/components/breadcrumbs/index.js:
--------------------------------------------------------------------------------
1 | import QBreadcrumbs from './QBreadcrumbs.js'
2 | import QBreadcrumbsEl from './QBreadcrumbsEl.js'
3 |
4 | export {
5 | QBreadcrumbs,
6 | QBreadcrumbsEl
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/filter.js:
--------------------------------------------------------------------------------
1 | export default function (terms, {field, list}) {
2 | const token = terms.toLowerCase()
3 | return list.filter(item => ('' + item[field]).toLowerCase().startsWith(token))
4 | }
5 |
--------------------------------------------------------------------------------
/dev/components/web-tests/c.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | CCC
4 | Go to A
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/components/chips-input/chips-input.ios.styl:
--------------------------------------------------------------------------------
1 | .q-input-chips
2 | margin-top -1px
3 | margin-bottom -1px
4 | .q-chip
5 | margin 1px
6 | input.q-input-target
7 | min-width 70px !important
8 |
--------------------------------------------------------------------------------
/src/components/chips-input/chips-input.mat.styl:
--------------------------------------------------------------------------------
1 | .q-input-chips
2 | margin-top -1px
3 | margin-bottom -1px
4 | .q-chip
5 | margin 1px
6 | input.q-input-target
7 | min-width 70px !important
8 |
--------------------------------------------------------------------------------
/src/components/card/QCardMain.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCardMain',
3 | render (h) {
4 | return h('div', {
5 | staticClass: 'q-card-main q-card-container'
6 | }, this.$slots.default)
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/css/ios.styl:
--------------------------------------------------------------------------------
1 | @import './core.variables'
2 | @import './variables.ios'
3 | @import './normalize'
4 | @import './critical'
5 | @import '../components/*/*.ios'
6 | @import './core/*'
7 | @import '../ie-compat/ie.ios'
8 |
--------------------------------------------------------------------------------
/src/css/mat.styl:
--------------------------------------------------------------------------------
1 | @import './core.variables'
2 | @import './variables.mat'
3 | @import './normalize'
4 | @import './critical'
5 | @import '../components/*/*.mat'
6 | @import './core/*'
7 | @import '../ie-compat/ie.mat'
8 |
--------------------------------------------------------------------------------
/src/components/pagination/pagination.ios.styl:
--------------------------------------------------------------------------------
1 | .q-pagination
2 | input
3 | text-align center
4 | .q-btn
5 | padding 0 5px !important
6 | &.disabled
7 | color $faded
8 | color var(--q-color-faded)
9 |
--------------------------------------------------------------------------------
/src/components/pagination/pagination.mat.styl:
--------------------------------------------------------------------------------
1 | .q-pagination
2 | input
3 | text-align center
4 | .q-btn
5 | padding 0 5px !important
6 | &.disabled
7 | color $faded
8 | color var(--q-color-faded)
9 |
--------------------------------------------------------------------------------
/src/css/core/touch.styl:
--------------------------------------------------------------------------------
1 | .q-touch
2 | user-select none
3 | user-drag none
4 | -khtml-user-drag none
5 | -webkit-user-drag none
6 | .q-touch-x
7 | touch-action pan-x
8 | .q-touch-y
9 | touch-action pan-y
10 |
--------------------------------------------------------------------------------
/src/components/fab/fab-mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | outline: Boolean,
4 | push: Boolean,
5 | flat: Boolean,
6 | color: String,
7 | textColor: String,
8 | glossy: Boolean
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .Thumbs.db
3 | node_modules/
4 | dev-umd/dist
5 | dist/
6 | deploy/
7 | npm-debug.log
8 | test/unit/coverage/
9 | test/e2e/dist/
10 | cordova
11 | *.sublime*
12 | .idea/
13 | debug.log
14 | package-lock.json
15 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | plugins: [
5 | // to edit target browsers: use "browserslist" field in package.json
6 | require('autoprefixer')
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/dev/components/web-tests/b.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | BBB
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/src/plugins/dialog.js:
--------------------------------------------------------------------------------
1 | import QDialog from '../components/dialog/QDialog.js'
2 | import modalFn from '../utils/modal-fn.js'
3 |
4 | export default {
5 | install ({ $q, Vue }) {
6 | this.create = $q.dialog = modalFn(QDialog, Vue)
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/dev/pages.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Export files list for /dev/components folder
3 | */
4 |
5 | export default require.context('./components', true, /^\.\/.*\.vue$/)
6 | .keys()
7 | .filter(page => page.split('/').length === 3)
8 | .map(page => page.slice(2))
9 |
--------------------------------------------------------------------------------
/src/components/stepper/index.js:
--------------------------------------------------------------------------------
1 | import QStep from './QStep.js'
2 | import QStepper from './QStepper.js'
3 | import QStepperNavigation from './QStepperNavigation.js'
4 |
5 | export {
6 | QStep,
7 | QStepper,
8 | QStepperNavigation
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/dot/dot.ios.styl:
--------------------------------------------------------------------------------
1 | .q-dot
2 | position absolute
3 | top $dot-position-top
4 | right $dot-position-right
5 | height $dot-size
6 | width $dot-size
7 | border-radius 50%
8 | background $dot-color
9 | opacity $dot-opacity
10 |
--------------------------------------------------------------------------------
/src/components/dot/dot.mat.styl:
--------------------------------------------------------------------------------
1 | .q-dot
2 | position absolute
3 | top $dot-position-top
4 | right $dot-position-right
5 | height $dot-size
6 | width $dot-size
7 | border-radius 50%
8 | background $dot-color
9 | opacity $dot-opacity
10 |
--------------------------------------------------------------------------------
/src/components/tab/index.js:
--------------------------------------------------------------------------------
1 | import QRouteTab from './QRouteTab.js'
2 | import QTab from './QTab.js'
3 | import QTabPane from './QTabPane.js'
4 | import QTabs from './QTabs.js'
5 |
6 | export {
7 | QRouteTab,
8 | QTab,
9 | QTabPane,
10 | QTabs
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/breadcrumbs/breadcrumbs.ios.styl:
--------------------------------------------------------------------------------
1 | .q-breadcrumbs
2 | .q-icon, .q-breadcrumbs-separator
3 | font-size 150%
4 | .q-breadcrumbs-last a
5 | pointer-events none
6 |
7 | [dir=rtl] .q-breadcrumbs-separator .q-icon
8 | transform scaleX(-1) /* rtl:ignore */
9 |
--------------------------------------------------------------------------------
/src/components/breadcrumbs/breadcrumbs.mat.styl:
--------------------------------------------------------------------------------
1 | .q-breadcrumbs
2 | .q-icon, .q-breadcrumbs-separator
3 | font-size 150%
4 | .q-breadcrumbs-last a
5 | pointer-events none
6 |
7 | [dir=rtl] .q-breadcrumbs-separator .q-icon
8 | transform scaleX(-1) /* rtl:ignore */
9 |
--------------------------------------------------------------------------------
/src/components/loading/loading.ios.styl:
--------------------------------------------------------------------------------
1 | body.with-loading
2 | overflow hidden
3 |
4 | .q-loading
5 | background $loading-background
6 | > div
7 | margin 40px 20px 0
8 | max-width 450px
9 | text-align center
10 | text-shadow 0 0 7px black
11 |
--------------------------------------------------------------------------------
/src/components/loading/loading.mat.styl:
--------------------------------------------------------------------------------
1 | body.with-loading
2 | overflow hidden
3 |
4 | .q-loading
5 | background $loading-background
6 | > div
7 | margin 40px 20px 0
8 | max-width 450px
9 | text-align center
10 | text-shadow 0 0 7px black
11 |
--------------------------------------------------------------------------------
/src/components/carousel/index.js:
--------------------------------------------------------------------------------
1 | import QCarousel from './QCarousel.js'
2 | import QCarouselSlide from './QCarouselSlide.js'
3 | import QCarouselControl from './QCarouselControl.js'
4 |
5 | export {
6 | QCarousel,
7 | QCarouselSlide,
8 | QCarouselControl
9 | }
10 |
--------------------------------------------------------------------------------
/src/plugins/action-sheet.js:
--------------------------------------------------------------------------------
1 | import QActionSheet from '../components/action-sheet/QActionSheet.js'
2 | import modalFn from '../utils/modal-fn.js'
3 |
4 | export default {
5 | install ({ $q, Vue }) {
6 | this.create = $q.actionSheet = modalFn(QActionSheet, Vue)
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/src/utils/uid.js:
--------------------------------------------------------------------------------
1 | function s4 () {
2 | return Math.floor((1 + Math.random()) * 0x10000)
3 | .toString(16)
4 | .substring(1)
5 | }
6 |
7 | export default function () {
8 | return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
9 | s4() + '-' + s4() + s4() + s4()
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/btn/index.js:
--------------------------------------------------------------------------------
1 | import QBtn from './QBtn.js'
2 | import QBtnGroup from './QBtnGroup.js'
3 | import QBtnDropdown from './QBtnDropdown.js'
4 | import QBtnToggle from './QBtnToggle.js'
5 |
6 | export {
7 | QBtn,
8 | QBtnGroup,
9 | QBtnDropdown,
10 | QBtnToggle
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/scroll-area/scroll-area.ios.styl:
--------------------------------------------------------------------------------
1 | .q-scrollarea-thumb
2 | background black
3 | width 10px
4 | right 0
5 | opacity .2
6 | transition opacity .3s
7 | &.invisible-thumb
8 | opacity 0 !important
9 | &:hover
10 | opacity .3
11 | &:active
12 | opacity .5
13 |
--------------------------------------------------------------------------------
/src/components/scroll-area/scroll-area.mat.styl:
--------------------------------------------------------------------------------
1 | .q-scrollarea-thumb
2 | background black
3 | width 10px
4 | right 0
5 | opacity .2
6 | transition opacity .3s
7 | &.invisible-thumb
8 | opacity 0 !important
9 | &:hover
10 | opacity .3
11 | &:active
12 | opacity .5
13 |
--------------------------------------------------------------------------------
/src/components/pull-to-refresh/pull-to-refresh.ios.styl:
--------------------------------------------------------------------------------
1 | .pull-to-refresh
2 | position relative
3 |
4 | .pull-to-refresh-message
5 | height 65px
6 | font-size $pull-to-refresh-font-size
7 | .q-icon
8 | font-size $pull-to-refresh-icon-size
9 | margin-right 15px
10 | transition all .3s
11 |
--------------------------------------------------------------------------------
/src/components/pull-to-refresh/pull-to-refresh.mat.styl:
--------------------------------------------------------------------------------
1 | .pull-to-refresh
2 | position relative
3 |
4 | .pull-to-refresh-message
5 | height 65px
6 | font-size $pull-to-refresh-font-size
7 | .q-icon
8 | font-size $pull-to-refresh-icon-size
9 | margin-right 15px
10 | transition all .3s
11 |
--------------------------------------------------------------------------------
/src/components/table/index.js:
--------------------------------------------------------------------------------
1 | import QTable from './QTable.js'
2 | import QTh from './QTh.js'
3 | import QTr from './QTr.js'
4 | import QTd from './QTd.js'
5 | import QTableColumns from './QTableColumns.js'
6 |
7 | export {
8 | QTable,
9 | QTh,
10 | QTr,
11 | QTd,
12 | QTableColumns
13 | }
14 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | general:
2 | branches:
3 | ignore:
4 | - gh-pages
5 | - dev
6 | machine:
7 | node:
8 | version: 4.2.0
9 | test:
10 | post:
11 | - cat /home/ubuntu/quasar-framework/test/unit/coverage/lcov.info | /home/ubuntu/quasar-framework/node_modules/codecov.io/bin/codecov.io.js
12 |
--------------------------------------------------------------------------------
/dev/components/web-tests/a.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | AAA
4 | Go to B
5 |
6 |
7 |
8 |
15 |
--------------------------------------------------------------------------------
/src/components/card/QCardSeparator.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCardSeparator',
3 | props: {
4 | inset: Boolean
5 | },
6 | render (h) {
7 | return h('div', {
8 | staticClass: 'q-card-separator',
9 | 'class': { inset: this.inset }
10 | }, this.$slots.default)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/observables/index.js:
--------------------------------------------------------------------------------
1 | import QResizeObservable from './QResizeObservable.js'
2 | import QScrollObservable from './QScrollObservable.js'
3 | import QWindowResizeObservable from './QWindowResizeObservable.js'
4 |
5 | export {
6 | QResizeObservable,
7 | QScrollObservable,
8 | QWindowResizeObservable
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/table/QTr.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QTr',
3 | props: {
4 | props: Object
5 | },
6 | render (h) {
7 | return h(
8 | 'tr',
9 | !this.props || this.props.header
10 | ? {}
11 | : { 'class': this.props.__trClass },
12 | this.$slots.default
13 | )
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/spinner/spinner-mixin.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | color: String,
4 | size: {
5 | type: [Number, String],
6 | default: '1em'
7 | }
8 | },
9 | computed: {
10 | classes () {
11 | if (this.color) {
12 | return `text-${this.color}`
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/mixins/can-render.js:
--------------------------------------------------------------------------------
1 | // using it to manage SSR rendering with best performance
2 | import { onSSR } from '../plugins/platform.js'
3 |
4 | export default {
5 | data () {
6 | return {
7 | canRender: !onSSR
8 | }
9 | },
10 | mounted () {
11 | this.canRender === false && (this.canRender = true)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/components/list/QListHeader.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QListHeader',
3 | props: {
4 | inset: Boolean
5 | },
6 | render (h) {
7 | return h('div', {
8 | staticClass: 'q-list-header',
9 | 'class': {
10 | 'q-list-header-inset': this.inset
11 | }
12 | }, this.$slots.default)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/tooltip/tooltip.mat.styl:
--------------------------------------------------------------------------------
1 | .q-tooltip
2 | position fixed
3 | font-size $tooltip-fontsize
4 | color $tooltip-color
5 | background $tooltip-background
6 | z-index $z-tooltip
7 | padding $tooltip-padding
8 | border-radius $tooltip-border-radius
9 | overflow-y auto
10 | overflow-x hidden
11 | pointer-events none
12 |
--------------------------------------------------------------------------------
/src/components/knob/knob.ios.styl:
--------------------------------------------------------------------------------
1 | .q-knob, .q-knob > div
2 | position relative
3 | display inline-block
4 | .q-knob > div
5 | width 100%
6 | height 100%
7 |
8 | .q-knob-label
9 | width 100%
10 | pointer-events none
11 | position absolute
12 | left 0
13 | right 0
14 | top 0
15 | bottom 0
16 |
17 | i
18 | font-size 130%
19 |
--------------------------------------------------------------------------------
/src/components/knob/knob.mat.styl:
--------------------------------------------------------------------------------
1 | .q-knob, .q-knob > div
2 | position relative
3 | display inline-block
4 | .q-knob > div
5 | width 100%
6 | height 100%
7 |
8 | .q-knob-label
9 | width 100%
10 | pointer-events none
11 | position absolute
12 | left 0
13 | right 0
14 | top 0
15 | bottom 0
16 |
17 | i
18 | font-size 130%
19 |
--------------------------------------------------------------------------------
/src/components/stepper/QStepperNavigation.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QStepperNavigation',
3 | render (h) {
4 | return h('div', {
5 | staticClass: 'q-stepper-nav order-last row items-center'
6 | }, [
7 | this.$slots.left,
8 | h('div', { staticClass: 'col' }),
9 | this.$slots.default
10 | ])
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/list/QItemSeparator.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QItemSeparator',
3 | props: {
4 | inset: Boolean
5 | },
6 | render (h) {
7 | return h('div', {
8 | staticClass: 'q-item-separator-component',
9 | 'class': {
10 | 'q-item-separator-inset-component': this.inset
11 | }
12 | }, this.$slots.default)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/utils/throttle.js:
--------------------------------------------------------------------------------
1 | export default function (fn, limit = 250) {
2 | let wait = false
3 | let result
4 |
5 | return function (...args) {
6 | if (wait) {
7 | return result
8 | }
9 |
10 | wait = true
11 | result = fn.apply(this, args)
12 | setTimeout(() => {
13 | wait = false
14 | }, limit)
15 | return result
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/vue-plugin.js:
--------------------------------------------------------------------------------
1 | import install from './install.js'
2 | import { version } from '../package.json'
3 | import i18n from './i18n.js'
4 | import icons from './icons.js'
5 | import ssrUpdate from './ssr-update.js'
6 |
7 | const theme = process.env.THEME
8 |
9 | export default {
10 | version,
11 | install,
12 | i18n,
13 | icons,
14 | theme,
15 | ssrUpdate
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/tooltip/tooltip.ios.styl:
--------------------------------------------------------------------------------
1 | .q-tooltip
2 | position fixed
3 | font-size $tooltip-fontsize
4 | color $tooltip-color
5 | background $tooltip-background
6 | box-shadow $tooltip-box-shadow
7 | z-index $z-tooltip
8 | padding $tooltip-padding
9 | border-radius $tooltip-border-radius
10 | overflow-y auto
11 | overflow-x hidden
12 | pointer-events none
13 |
--------------------------------------------------------------------------------
/src/css/critical.styl:
--------------------------------------------------------------------------------
1 | .q-icon
2 | line-height 1
3 | letter-spacing normal
4 | text-transform none
5 | white-space nowrap
6 | word-wrap normal
7 | direction ltr
8 |
9 | .q-icon, .material-icons
10 | user-select none
11 | cursor inherit
12 | font-size inherit
13 | display inline-flex
14 | align-items center
15 | justify-content center
16 | vertical-align middle
17 |
--------------------------------------------------------------------------------
/src/components/parallax/parallax.ios.styl:
--------------------------------------------------------------------------------
1 | .q-parallax
2 | position relative
3 | width 100%
4 | overflow hidden
5 | border-radius inherit
6 |
7 | .q-parallax-media
8 | > img, > video
9 | position absolute
10 | left 50%
11 | bottom 0
12 | min-width 100%
13 | min-height 100%
14 | will-change transform
15 |
16 | .q-parallax-text
17 | text-shadow $paralax-text-shadow
18 |
--------------------------------------------------------------------------------
/src/components/parallax/parallax.mat.styl:
--------------------------------------------------------------------------------
1 | .q-parallax
2 | position relative
3 | width 100%
4 | overflow hidden
5 | border-radius inherit
6 |
7 | .q-parallax-media
8 | > img, > video
9 | position absolute
10 | left 50%
11 | bottom 0
12 | min-width 100%
13 | min-height 100%
14 | will-change transform
15 |
16 | .q-parallax-text
17 | text-shadow $paralax-text-shadow
18 |
--------------------------------------------------------------------------------
/src/components/popover/popover.ios.styl:
--------------------------------------------------------------------------------
1 | .q-popover
2 | position fixed
3 | box-shadow $popover-box-shadow
4 | border-radius $generic-border-radius
5 | background $popover-background
6 | z-index $z-popover
7 | overflow-y auto
8 | overflow-x hidden
9 | max-width $popover-max-width
10 | outline 0
11 | > .q-list:only-child
12 | border none
13 |
14 | body div .q-popover
15 | display none
16 |
--------------------------------------------------------------------------------
/src/components/popover/popover.mat.styl:
--------------------------------------------------------------------------------
1 | .q-popover
2 | position fixed
3 | box-shadow $popover-box-shadow
4 | border-radius $generic-border-radius
5 | background $popover-background
6 | z-index $z-popover
7 | overflow-y auto
8 | overflow-x hidden
9 | max-width $popover-max-width
10 | outline 0
11 | > .q-list:only-child
12 | border none
13 |
14 | body div .q-popover
15 | display none
16 |
--------------------------------------------------------------------------------
/src/components/video/video.ios.styl:
--------------------------------------------------------------------------------
1 | img
2 | &.responsive
3 | max-width 100%
4 | height auto
5 | &.avatar
6 | width 50px
7 | height 50px
8 | border-radius 50%
9 | box-shadow $shadow-1
10 | vertical-align middle
11 |
12 | .q-video
13 | position relative
14 | overflow hidden
15 | border-radius inherit
16 |
17 | iframe, object, embed
18 | width 100%
19 | height 100%
20 |
--------------------------------------------------------------------------------
/src/components/video/video.mat.styl:
--------------------------------------------------------------------------------
1 | img
2 | &.responsive
3 | max-width 100%
4 | height auto
5 | &.avatar
6 | width 50px
7 | height 50px
8 | border-radius 50%
9 | box-shadow $shadow-1
10 | vertical-align middle
11 |
12 | .q-video
13 | position relative
14 | overflow hidden
15 | border-radius inherit
16 |
17 | iframe, object, embed
18 | width 100%
19 | height 100%
20 |
--------------------------------------------------------------------------------
/src/components/card/index.js:
--------------------------------------------------------------------------------
1 | import QCard from './QCard.js'
2 | import QCardTitle from './QCardTitle.js'
3 | import QCardMain from './QCardMain.js'
4 | import QCardActions from './QCardActions.js'
5 | import QCardMedia from './QCardMedia.js'
6 | import QCardSeparator from './QCardSeparator.js'
7 |
8 | export {
9 | QCard,
10 | QCardTitle,
11 | QCardMain,
12 | QCardActions,
13 | QCardMedia,
14 | QCardSeparator
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/open-url.js:
--------------------------------------------------------------------------------
1 | import Platform from '../plugins/platform.js'
2 |
3 | export default (url, reject) => {
4 | if (Platform.is.cordova && navigator && navigator.app) {
5 | return navigator.app.loadUrl(url, {
6 | openExternal: true
7 | })
8 | }
9 |
10 | let win = window.open(url, '_blank')
11 |
12 | if (win) {
13 | win.focus()
14 | return win
15 | }
16 | else {
17 | reject()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/utils/frame-debounce.js:
--------------------------------------------------------------------------------
1 | export default function (fn) {
2 | let wait = false, frame
3 |
4 | function debounced (...args) {
5 | if (wait) { return }
6 |
7 | wait = true
8 | frame = requestAnimationFrame(() => {
9 | fn.apply(this, args)
10 | wait = false
11 | })
12 | }
13 |
14 | debounced.cancel = () => {
15 | window.cancelAnimationFrame(frame)
16 | wait = false
17 | }
18 |
19 | return debounced
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/alert/alert.ios.styl:
--------------------------------------------------------------------------------
1 | .q-alert
2 | border-radius $generic-border-radius
3 | box-shadow none
4 |
5 | .avatar
6 | width 32px
7 | height 32px
8 |
9 | .q-alert-side, .q-alert-content
10 | padding 12px
11 | font-size 16px
12 | word-break break-word
13 |
14 | .q-alert-side
15 | font-size 24px
16 | background rgba(0, 0, 0, .1)
17 |
18 | .q-alert-actions
19 | padding 12px 12px 12px 0
20 |
21 | .q-alert-detail
22 | font-size 12px
23 |
--------------------------------------------------------------------------------
/src/components/alert/alert.mat.styl:
--------------------------------------------------------------------------------
1 | .q-alert
2 | border-radius $generic-border-radius
3 | box-shadow none
4 |
5 | .avatar
6 | width 32px
7 | height 32px
8 |
9 | .q-alert-side, .q-alert-content
10 | padding 12px
11 | font-size 16px
12 | word-break break-word
13 |
14 | .q-alert-side
15 | font-size 24px
16 | background rgba(0, 0, 0, .1)
17 |
18 | .q-alert-actions
19 | padding 12px 12px 12px 0
20 |
21 | .q-alert-detail
22 | font-size 12px
23 |
--------------------------------------------------------------------------------
/src/mixins/display-mode.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | popover: Boolean,
4 | modal: Boolean
5 | },
6 | computed: {
7 | isPopover () {
8 | // Explicit popover / modal choice
9 | if (this.popover) return true
10 | if (this.modal) return false
11 |
12 | // Automatically determine the default popover or modal behavior
13 | return this.$q.platform.is.desktop && !this.$q.platform.within.iframe
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/toolbar/QToolbarTitle.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QToolbarTitle',
3 | props: {
4 | shrink: Boolean
5 | },
6 | render (h) {
7 | return h('div', {
8 | staticClass: 'q-toolbar-title',
9 | 'class': this.shrink ? 'col-auto' : null
10 | }, [
11 | this.$slots.default,
12 | this.$slots.subtitle
13 | ? h('div', { staticClass: 'q-toolbar-subtitle' }, this.$slots.subtitle)
14 | : null
15 | ])
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/plugins/local-storage.js:
--------------------------------------------------------------------------------
1 | import { onSSR, hasWebStorage } from './platform.js'
2 | import { getEmptyStorage, getStorage } from '../utils/web-storage.js'
3 |
4 | export default {
5 | install ({ $q }) {
6 | if (onSSR) {
7 | $q.localStorage = getEmptyStorage()
8 | return
9 | }
10 |
11 | if (hasWebStorage()) {
12 | const storage = getStorage('local')
13 | $q.localStorage = storage
14 | Object.assign(this, storage)
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/sort.js:
--------------------------------------------------------------------------------
1 | export function sortString (a, b) {
2 | if (typeof a !== 'string') {
3 | throw new TypeError('The value for sorting must be a String')
4 | }
5 | return a.localeCompare(b)
6 | }
7 |
8 | export function sortNumber (a, b) {
9 | return a - b
10 | }
11 |
12 | export function sortDate (a, b) {
13 | return (new Date(a)) - (new Date(b))
14 | }
15 |
16 | export function sortBoolean (a, b) {
17 | return a && !b
18 | ? -1
19 | : (!a && b ? 1 : 0)
20 | }
21 |
--------------------------------------------------------------------------------
/dev/app.entry-client.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import { createApp } from './app'
3 | import { QAjaxBar } from 'quasar'
4 |
5 | const bar = new Vue(QAjaxBar).$mount()
6 | document.body.appendChild(bar.$el)
7 |
8 | const { app, router } = createApp()
9 |
10 | router.onReady(() => {
11 | router.beforeResolve((to, from, next) => {
12 | bar.start()
13 | next()
14 | })
15 | router.afterEach((to, from, next) => {
16 | bar.stop()
17 | })
18 | app.$mount('#q-app')
19 | })
20 |
--------------------------------------------------------------------------------
/src/plugins/session-storage.js:
--------------------------------------------------------------------------------
1 | import { onSSR, hasWebStorage } from './platform.js'
2 | import { getEmptyStorage, getStorage } from '../utils/web-storage.js'
3 |
4 | export default {
5 | install ({ $q }) {
6 | if (onSSR) {
7 | $q.sessionStorage = getEmptyStorage()
8 | return
9 | }
10 |
11 | if (hasWebStorage()) {
12 | const storage = getStorage('session')
13 | $q.sessionStorage = storage
14 | Object.assign(this, storage)
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "./src/**/*"
4 | ],
5 | "compilerOptions": {
6 | "baseUrl": ".",
7 | "paths": {
8 | "components/*": [
9 | "src/components/*"
10 | ],
11 | "directives/*": [
12 | "src/directives/*"
13 | ],
14 | "mixins/*": [
15 | "src/mixins/*"
16 | ],
17 | "plugins/*": [
18 | "src/plugins/*"
19 | ],
20 | "utils/*": [
21 | "src/utils/*"
22 | ]
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/option-group/option-group.mat.styl:
--------------------------------------------------------------------------------
1 | .q-option-inner
2 | display inline-block
3 | line-height 0
4 |
5 | & + .q-option-label
6 | margin-left $label-offset
7 |
8 | .q-option
9 | vertical-align middle
10 | input
11 | display none !important
12 | &.reverse .q-option-inner + .q-option-label
13 | margin-right $label-offset
14 | margin-left 0
15 |
16 | .q-option-group-inline-opts > div
17 | display inline-flex
18 | .q-option-group
19 | margin -5px
20 | padding 5px 0
21 |
--------------------------------------------------------------------------------
/src/components/layout/index.js:
--------------------------------------------------------------------------------
1 | import QLayout from './QLayout.js'
2 | import QLayoutDrawer from './QLayoutDrawer.js'
3 | import QLayoutFooter from './QLayoutFooter.js'
4 | import QLayoutHeader from './QLayoutHeader.js'
5 | import QPage from './QPage.js'
6 | import QPageContainer from './QPageContainer.js'
7 | import QPageSticky from './QPageSticky.js'
8 |
9 | export {
10 | QLayout,
11 | QLayoutDrawer,
12 | QLayoutFooter,
13 | QLayoutHeader,
14 | QPage,
15 | QPageContainer,
16 | QPageSticky
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/jumbotron/jumbotron.ios.styl:
--------------------------------------------------------------------------------
1 | .q-jumbotron
2 | position relative
3 | padding $jumbotron-padding
4 | border-radius $jumbotron-border-radius
5 | background-color $jumbotron-bg
6 | background-repeat no-repeat
7 | background-size cover
8 | .q-jumbotron-dark
9 | color $jumbotron-dark-color
10 | background-color $jumbotron-dark-bg
11 | hr.q-hr
12 | background rgba(255, 255, 255, .36)
13 |
14 | @media (min-width $breakpoint-md-min)
15 | .q-jumbotron
16 | padding $jumbotron-large-padding
17 |
--------------------------------------------------------------------------------
/src/components/jumbotron/jumbotron.mat.styl:
--------------------------------------------------------------------------------
1 | .q-jumbotron
2 | position relative
3 | padding $jumbotron-padding
4 | border-radius $jumbotron-border-radius
5 | background-color $jumbotron-bg
6 | background-repeat no-repeat
7 | background-size cover
8 | .q-jumbotron-dark
9 | color $jumbotron-dark-color
10 | background-color $jumbotron-dark-bg
11 | hr.q-hr
12 | background rgba(255, 255, 255, .36)
13 |
14 | @media (min-width $breakpoint-md-min)
15 | .q-jumbotron
16 | padding $jumbotron-large-padding
17 |
--------------------------------------------------------------------------------
/src/mixins/align.js:
--------------------------------------------------------------------------------
1 | const
2 | alignMap = {
3 | left: 'start',
4 | center: 'center',
5 | right: 'end',
6 | between: 'between',
7 | around: 'around'
8 | },
9 | alignValues = Object.keys(alignMap)
10 |
11 | export default {
12 | props: {
13 | align: {
14 | type: String,
15 | default: 'center',
16 | validator: v => alignValues.includes(v)
17 | }
18 | },
19 | computed: {
20 | alignClass () {
21 | return `justify-${alignMap[this.align]}`
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/list/index.js:
--------------------------------------------------------------------------------
1 | import QItem from './QItem.js'
2 | import QItemSeparator from './QItemSeparator.js'
3 | import QItemMain from './QItemMain.js'
4 | import QItemSide from './QItemSide.js'
5 | import QItemTile from './QItemTile.js'
6 | import QItemWrapper from './QItemWrapper.js'
7 | import QList from './QList.js'
8 | import QListHeader from './QListHeader.js'
9 |
10 | export {
11 | QItem,
12 | QItemSeparator,
13 | QItemMain,
14 | QItemSide,
15 | QItemTile,
16 | QItemWrapper,
17 | QList,
18 | QListHeader
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/card/QCardTitle.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCardTitle',
3 | render (h) {
4 | return h('div', {
5 | staticClass: 'q-card-primary q-card-container row no-wrap'
6 | }, [
7 | h('div', {staticClass: 'col column'}, [
8 | h('div', {staticClass: 'q-card-title'}, this.$slots.default),
9 | h('div', {staticClass: 'q-card-subtitle'}, [ this.$slots.subtitle ])
10 | ]),
11 | h('div', {staticClass: 'col-auto self-center q-card-title-extra'}, [ this.$slots.right ])
12 | ])
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/video/QVideo.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QVideo',
3 | props: {
4 | src: {
5 | type: String,
6 | required: true
7 | }
8 | },
9 | computed: {
10 | iframeData () {
11 | return {
12 | attrs: {
13 | src: this.src,
14 | frameborder: '0',
15 | allowfullscreen: true
16 | }
17 | }
18 | }
19 | },
20 | render (h) {
21 | return h('div', {
22 | staticClass: 'q-video'
23 | }, [
24 | h('iframe', this.iframeData)
25 | ])
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/css/core/elevation.styl:
--------------------------------------------------------------------------------
1 | .shadow-transition
2 | transition $shadow-transition !important
3 |
4 | for $z in 1..24
5 | .shadow-{$z}
6 | box-shadow $shadow-+$z
7 | .shadow-up-{$z}
8 | box-shadow $shadow-up-+$z
9 |
10 | .no-shadow, .shadow-0
11 | box-shadow none !important
12 | .inset-shadow
13 | box-shadow $inset-shadow !important
14 |
15 | .z-marginals
16 | z-index $z-marginals
17 |
18 | .z-notify
19 | z-index $z-notify
20 |
21 | .z-fullscreen
22 | z-index $z-fullscreen
23 |
24 | .z-inherit
25 | z-index inherit !important
26 |
--------------------------------------------------------------------------------
/src/utils/debounce.js:
--------------------------------------------------------------------------------
1 | export default function (fn, wait = 250, immediate) {
2 | let timeout
3 |
4 | function debounced (...args) {
5 | const later = () => {
6 | timeout = null
7 | if (!immediate) {
8 | fn.apply(this, args)
9 | }
10 | }
11 |
12 | clearTimeout(timeout)
13 | if (immediate && !timeout) {
14 | fn.apply(this, args)
15 | }
16 | timeout = setTimeout(later, wait)
17 | }
18 |
19 | debounced.cancel = () => {
20 | clearTimeout(timeout)
21 | }
22 |
23 | return debounced
24 | }
25 |
--------------------------------------------------------------------------------
/dev/components/components/video-embedding.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
With Component
5 |
8 |
9 |
With HTML Markup
10 |
11 | VIDEO
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/index.esm.js:
--------------------------------------------------------------------------------
1 | import VuePlugin from './vue-plugin.js'
2 |
3 | import * as components from './components.js'
4 | import * as directives from './directives.js'
5 | import * as plugins from './plugins.js'
6 |
7 | export * from './components.js'
8 | export * from './directives.js'
9 | export * from './plugins.js'
10 | export * from './utils.js'
11 |
12 | export default {
13 | ...VuePlugin,
14 | install (Vue, opts) {
15 | VuePlugin.install(Vue, {
16 | components,
17 | directives,
18 | plugins,
19 | ...opts
20 | })
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/radio/radio.ios.styl:
--------------------------------------------------------------------------------
1 | $radio-size = 21px
2 |
3 | .q-radio-unchecked, .q-radio-checked, .q-radio .q-option-inner
4 | height $radio-size
5 | width $radio-size
6 | min-width $radio-size
7 | font-size $radio-size
8 | transition transform .45s cubic-bezier(.23, 1, .32, 1)
9 | opacity 1
10 |
11 | .q-radio-unchecked
12 | opacity 1
13 | .q-radio-checked
14 | transform-origin 50% 50% 0
15 | transform scale(0)
16 |
17 | .q-radio .q-option-inner.active
18 | .q-radio-unchecked
19 | opacity 0
20 | .q-radio-checked
21 | transform scale(1)
22 |
--------------------------------------------------------------------------------
/src/components/radio/radio.mat.styl:
--------------------------------------------------------------------------------
1 | $radio-size = 21px
2 |
3 | .q-radio-unchecked, .q-radio-checked, .q-radio .q-option-inner
4 | height $radio-size
5 | width $radio-size
6 | min-width $radio-size
7 | font-size $radio-size
8 | transition transform .45s cubic-bezier(.23, 1, .32, 1)
9 | opacity 1
10 |
11 | .q-radio-unchecked
12 | opacity 1
13 | .q-radio-checked
14 | transform-origin 50% 50% 0
15 | transform scale(0)
16 |
17 | .q-radio .q-option-inner.active
18 | .q-radio-unchecked
19 | opacity 0
20 | .q-radio-checked
21 | transform scale(1)
22 |
--------------------------------------------------------------------------------
/src/css/core/orientation.styl:
--------------------------------------------------------------------------------
1 | .rotate-45
2 | transform rotate(45deg) /* rtl:ignore */
3 | .rotate-90
4 | transform rotate(90deg) /* rtl:ignore */
5 | .rotate-135
6 | transform rotate(135deg) /* rtl:ignore */
7 | .rotate-180
8 | transform rotate(180deg) /* rtl:ignore */
9 | .rotate-205
10 | transform rotate(205deg) /* rtl:ignore */
11 | .rotate-270
12 | transform rotate(270deg) /* rtl:ignore */
13 | .rotate-315
14 | transform rotate(315deg) /* rtl:ignore */
15 | .flip-horizontal
16 | transform scale(-1, 1)
17 | .flip-vertical
18 | transform scale(1, -1)
19 |
--------------------------------------------------------------------------------
/src/components/ajax-bar/ajax-bar.ios.styl:
--------------------------------------------------------------------------------
1 | .q-loading-bar
2 | position fixed
3 | z-index $z-max
4 | transition transform .5s cubic-bezier(0, 0, .2, 1), opacity .5s
5 |
6 | &.top
7 | left 0 /* rtl:ignore */
8 | right 0 /* rtl:ignore */
9 | top 0
10 | width 100%
11 | &.bottom
12 | left 0 /* rtl:ignore */
13 | right 0 /* rtl:ignore */
14 | bottom 0
15 | width 100%
16 |
17 | &.right
18 | top 0
19 | bottom 0
20 | right 0
21 | height 100%
22 | &.left
23 | top 0
24 | bottom 0
25 | left 0
26 | height 100%
27 |
--------------------------------------------------------------------------------
/src/components/ajax-bar/ajax-bar.mat.styl:
--------------------------------------------------------------------------------
1 | .q-loading-bar
2 | position fixed
3 | z-index $z-max
4 | transition transform .5s cubic-bezier(0, 0, .2, 1), opacity .5s
5 |
6 | &.top
7 | left 0 /* rtl:ignore */
8 | right 0 /* rtl:ignore */
9 | top 0
10 | width 100%
11 | &.bottom
12 | left 0 /* rtl:ignore */
13 | right 0 /* rtl:ignore */
14 | bottom 0
15 | width 100%
16 |
17 | &.right
18 | top 0
19 | bottom 0
20 | right 0
21 | height 100%
22 | &.left
23 | top 0
24 | bottom 0
25 | left 0
26 | height 100%
27 |
--------------------------------------------------------------------------------
/src/components/btn/QBtnGroup.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QBtnGroup',
3 | props: {
4 | outline: Boolean,
5 | flat: Boolean,
6 | rounded: Boolean,
7 | push: Boolean
8 | },
9 | computed: {
10 | classes () {
11 | return ['outline', 'flat', 'rounded', 'push']
12 | .filter(t => this[t])
13 | .map(t => `q-btn-group-${t}`).join(' ')
14 | }
15 | },
16 | render (h) {
17 | return h('div', {
18 | staticClass: 'q-btn-group row no-wrap inline',
19 | 'class': this.classes
20 | }, this.$slots.default)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/dev/components/touch-directives/touch-style.styl:
--------------------------------------------------------------------------------
1 | @import '~variables'
2 |
3 | .docs-touch
4 | .custom-area
5 | height 350px
6 | border-radius 3px
7 | cursor pointer
8 | color white
9 | background $primary
10 | box-shadow $shadow-2
11 | position relative
12 |
13 | .custom-info pre
14 | width 250px
15 |
16 | .touch-signal
17 | position absolute
18 | bottom 16px
19 | right 16px
20 | width 35px
21 | height 35px
22 | font-size 25px
23 | border-radius 50%
24 | text-align center
25 | background rgba(255, 255, 255, .2)
26 |
--------------------------------------------------------------------------------
/src/components/option-group/option-group.ios.styl:
--------------------------------------------------------------------------------
1 | .q-option-inner
2 | display inline-block
3 | line-height 0
4 |
5 | &.active
6 | color $primary
7 | color var(--q-color-primary)
8 | & + .q-option-label
9 | margin-left $label-offset
10 |
11 | .q-option
12 | vertical-align middle
13 | input
14 | display none !important
15 | &.reverse .q-option-inner + .q-option-label
16 | margin-right $label-offset
17 | margin-left 0
18 |
19 | .q-option-group-inline-opts > div
20 | display inline-flex
21 | .q-option-group
22 | margin -5px
23 | padding 5px 0
24 |
--------------------------------------------------------------------------------
/src/icons.js:
--------------------------------------------------------------------------------
1 | import { isSSR } from './plugins/platform.js'
2 | import materialIcons from '../icons/material-icons.js'
3 |
4 | export default {
5 | __installed: false,
6 | install ($q, Vue, iconSet) {
7 | this.set = (iconDef = materialIcons) => {
8 | iconDef.set = this.set
9 |
10 | if (isSSR || $q.icon) {
11 | $q.icon = iconDef
12 | }
13 | else {
14 | Vue.util.defineReactive($q, 'icon', iconDef)
15 | }
16 |
17 | this.name = iconDef.name
18 | this.def = iconDef
19 | }
20 |
21 | this.set(iconSet)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/rating/rating.ios.styl:
--------------------------------------------------------------------------------
1 | .q-rating
2 | color $rating-grade-color
3 | vertical-align middle
4 |
5 | span
6 | pointer-events none
7 | display inherit
8 | i
9 | color currentColor
10 | text-shadow $rating-shadow
11 | position relative
12 | cursor default
13 | opacity .4
14 | pointer-events all
15 | &.hovered
16 | transform scale(1.3)
17 | &.exselected
18 | opacity .7
19 | &.active
20 | opacity 1
21 | & + i
22 | margin-left .3rem
23 |
24 |
25 | &.editable i
26 | cursor pointer
27 | &:not(.editable) span, i
28 | outline 0
29 |
--------------------------------------------------------------------------------
/src/components/rating/rating.mat.styl:
--------------------------------------------------------------------------------
1 | .q-rating
2 | color $rating-grade-color
3 | vertical-align middle
4 |
5 | span
6 | pointer-events none
7 | display inherit
8 | i
9 | color currentColor
10 | text-shadow $rating-shadow
11 | position relative
12 | cursor default
13 | opacity .4
14 | pointer-events all
15 | &.hovered
16 | transform scale(1.3)
17 | &.exselected
18 | opacity .7
19 | &.active
20 | opacity 1
21 | & + i
22 | margin-left .3rem
23 |
24 |
25 | &.editable i
26 | cursor pointer
27 | &:not(.editable) span, i
28 | outline 0
29 |
--------------------------------------------------------------------------------
/src/components/toolbar/toolbar.mat.styl:
--------------------------------------------------------------------------------
1 | .q-toolbar
2 | padding $toolbar-padding
3 | min-height $toolbar-min-height
4 | overflow hidden
5 | width 100%
6 | .q-toolbar-inverted
7 | background white
8 |
9 | .q-toolbar-title
10 | flex 1 1 0%
11 | min-width 1px
12 | max-width 100%
13 | font-size $toolbar-title-font-size
14 | font-weight $toolbar-title-font-weight
15 | padding $toolbar-title-padding
16 |
17 | .q-toolbar-subtitle
18 | font-size $toolbar-subtitle-font-size
19 | opacity .7
20 |
21 | .q-toolbar-title, .q-toolbar-subtitle
22 | text-overflow ellipsis
23 | white-space nowrap
24 | overflow hidden
25 |
--------------------------------------------------------------------------------
/src/css/core/mouse.styl:
--------------------------------------------------------------------------------
1 | .non-selectable
2 | user-select none !important
3 |
4 | .scroll
5 | overflow auto
6 | .scroll, .scroll-x, .scroll-y
7 | -webkit-overflow-scrolling touch
8 | will-change scroll-position
9 | .scroll-x
10 | overflow-x auto
11 | .scroll-y
12 | overflow-y auto
13 | .no-scroll
14 | overflow hidden !important
15 |
16 | .no-pointer-events
17 | pointer-events none !important
18 | .all-pointer-events
19 | pointer-events all !important
20 |
21 | .cursor-pointer
22 | cursor pointer !important
23 | .cursor-not-allowed
24 | cursor not-allowed !important
25 | .cursor-inherit
26 | cursor inherit !important
27 |
--------------------------------------------------------------------------------
/src/components/spinner/spinner.mat.styl:
--------------------------------------------------------------------------------
1 | .q-spinner
2 | vertical-align middle
3 |
4 | .q-spinner-mat
5 | animation q-spin 2s linear infinite /* rtl:ignore */
6 | transform-origin center center /* rtl:ignore */
7 | .path
8 | stroke-dasharray 1, 200
9 | stroke-dashoffset 0
10 | stroke-linecap round
11 | animation q-mat-dash 1.5s ease-in-out infinite /* rtl:ignore */
12 |
13 | @keyframes q-mat-dash
14 | 0%
15 | stroke-dasharray 1, 200
16 | stroke-dashoffset 0
17 | 50%
18 | stroke-dasharray 89, 200
19 | stroke-dashoffset -35px
20 | 100%
21 | stroke-dasharray 89, 200
22 | stroke-dashoffset -124px
23 |
--------------------------------------------------------------------------------
/dev/components/web-tests/fast-test.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
24 |
25 |
29 |
--------------------------------------------------------------------------------
/src/components/spinner/spinner.ios.styl:
--------------------------------------------------------------------------------
1 | .q-spinner
2 | vertical-align middle
3 |
4 | .q-spinner-mat
5 | animation q-spin 2s linear infinite /* rtl:ignore */
6 | transform-origin center center /* rtl:ignore */
7 | .path
8 | stroke-dasharray 1, 200
9 | stroke-dashoffset 0
10 | stroke-linecap round
11 | animation q-mat-dash 1.5s ease-in-out infinite /* rtl:ignore */
12 |
13 | @keyframes q-mat-dash
14 | 0%
15 | stroke-dasharray 1, 200
16 | stroke-dashoffset 0
17 | 50%
18 | stroke-dasharray 89, 200
19 | stroke-dashoffset -35px
20 | 100%
21 | stroke-dasharray 89, 200
22 | stroke-dashoffset -124px
23 |
--------------------------------------------------------------------------------
/src/components/table/table-filter.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | filter: [String, Object],
4 | filterMethod: {
5 | type: Function,
6 | default (rows, terms, cols = this.computedCols, cellValue = this.getCellValue) {
7 | const lowerTerms = terms ? terms.toLowerCase() : ''
8 | return rows.filter(
9 | row => cols.some(col => (cellValue(col, row) + '').toLowerCase().indexOf(lowerTerms) !== -1)
10 | )
11 | }
12 | }
13 | },
14 | watch: {
15 | filter () {
16 | this.$nextTick(() => {
17 | this.setPagination({ page: 1 }, true)
18 | })
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/timeline/QTimeline.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QTimeline',
3 | provide () {
4 | return {
5 | __timeline: this
6 | }
7 | },
8 | props: {
9 | color: {
10 | type: String,
11 | default: 'primary'
12 | },
13 | responsive: Boolean,
14 | noHover: Boolean,
15 | dark: Boolean
16 | },
17 | render (h) {
18 | return h('ul', {
19 | staticClass: 'q-timeline',
20 | 'class': {
21 | 'q-timeline-dark': this.dark,
22 | 'q-timeline-responsive': this.responsive,
23 | 'q-timeline-hover': !this.noHover
24 | }
25 | }, this.$slots.default)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/directives.js:
--------------------------------------------------------------------------------
1 | import BackToTop from './directives/back-to-top.js'
2 | import CloseOverlay from './directives/close-overlay.js'
3 | import GoBack from './directives/go-back.js'
4 | import Ripple from './directives/ripple.js'
5 | import ScrollFire from './directives/scroll-fire.js'
6 | import Scroll from './directives/scroll.js'
7 | import TouchHold from './directives/touch-hold.js'
8 | import TouchPan from './directives/touch-pan.js'
9 | import TouchSwipe from './directives/touch-swipe.js'
10 |
11 | export {
12 | BackToTop,
13 | CloseOverlay,
14 | GoBack,
15 | Ripple,
16 | ScrollFire,
17 | Scroll,
18 | TouchHold,
19 | TouchPan,
20 | TouchSwipe
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/card/QCardMedia.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCardMedia',
3 | props: {
4 | overlayPosition: {
5 | type: String,
6 | default: 'bottom',
7 | validator: v => ['top', 'bottom', 'full'].includes(v)
8 | }
9 | },
10 | render (h) {
11 | return h('div', {
12 | staticClass: 'q-card-media relative-position'
13 | }, [
14 | this.$slots.default,
15 | this.$slots.overlay
16 | ? h('div', {
17 | staticClass: 'q-card-media-overlay',
18 | 'class': `absolute-${this.overlayPosition}`
19 | }, [
20 | this.$slots.overlay
21 | ])
22 | : null
23 | ])
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/components/toolbar/toolbar.ios.styl:
--------------------------------------------------------------------------------
1 | .q-toolbar
2 | padding $toolbar-padding
3 | min-height $toolbar-min-height
4 | overflow hidden
5 | width 100%
6 | .q-toolbar-inverted
7 | background white
8 |
9 | .q-toolbar-title
10 | flex 1 1 0%
11 | min-width 1px
12 | max-width 100%
13 | align-items center
14 | font-size $toolbar-title-font-size
15 | font-weight $toolbar-title-font-weight
16 | padding $toolbar-title-padding
17 | text-align center
18 |
19 | .q-toolbar-subtitle
20 | font-size $toolbar-subtitle-font-size
21 | opacity .7
22 |
23 | .q-toolbar-title, .q-toolbar-subtitle
24 | text-overflow ellipsis
25 | white-space nowrap
26 | overflow hidden
27 |
--------------------------------------------------------------------------------
/src/components/card/QCardActions.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCardActions',
3 | props: {
4 | vertical: Boolean,
5 | align: {
6 | type: String,
7 | default: 'start',
8 | validator: v => ['start', 'center', 'end', 'around', 'between'].includes(v)
9 | }
10 | },
11 | computed: {
12 | classes () {
13 | return `q-card-actions-${this.vertical ? 'vert column justify-start' : 'horiz row'} ` +
14 | `${this.vertical ? 'items' : 'justify'}-${this.align}`
15 | }
16 | },
17 | render (h) {
18 | return h('div', {
19 | staticClass: 'q-card-actions',
20 | 'class': this.classes
21 | }, this.$slots.default)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/mixins/parent-field.js:
--------------------------------------------------------------------------------
1 | export default {
2 | inject: {
3 | field: {
4 | from: '__field',
5 | default: null
6 | }
7 | },
8 | props: {
9 | noParentField: Boolean
10 | },
11 | watch: {
12 | noParentField (val) {
13 | if (!this.field) {
14 | return
15 | }
16 | this.field[val ? '__registerInput' : '__unregisterInput'](this)
17 | }
18 | },
19 | beforeMount () {
20 | if (!this.noParentField && this.field) {
21 | this.field.__registerInput(this)
22 | }
23 | },
24 | beforeDestroy () {
25 | if (!this.noParentField && this.field) {
26 | this.field.__unregisterInput(this)
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/components/action-sheet/action-sheet.mat.styl:
--------------------------------------------------------------------------------
1 | .q-actionsheet-title
2 | min-height 56px
3 | padding 0 16px
4 | color $faded
5 | color var(--q-color-faded)
6 |
7 | .q-actionsheet-body
8 | max-height 500px
9 |
10 | .q-actionsheet-grid
11 | padding 8px 16px
12 | .q-item-separator-component
13 | margin 24px 0
14 |
15 | .q-actionsheet-grid-item
16 | padding 8px 16px
17 | transition background .3s
18 | &:hover, &:focus
19 | background $action-sheet-hover-background
20 | outline 0
21 | i, img
22 | font-size 48px
23 | margin-bottom 8px
24 | .avatar
25 | width 48px
26 | height 48px
27 | span
28 | color $faded
29 | color var(--q-color-faded)
30 |
--------------------------------------------------------------------------------
/src/ssr-update.js:
--------------------------------------------------------------------------------
1 | import { $q, queues } from './install.js'
2 |
3 | const mixin = {
4 | mounted () {
5 | queues.takeover.forEach(run => {
6 | run(this.$q)
7 | })
8 | }
9 | }
10 |
11 | export default function (ctx) {
12 | if (ctx.ssr) {
13 | const q = Object.assign({}, $q)
14 |
15 | Object.assign(ctx.ssr, {
16 | Q_HEAD_TAGS: '',
17 | Q_BODY_ATTRS: '',
18 | Q_BODY_TAGS: ''
19 | })
20 |
21 | queues.server.forEach(run => {
22 | run(q, ctx)
23 | })
24 |
25 | ctx.app.$q = q
26 | }
27 | else {
28 | const mixins = ctx.app.mixins || []
29 | if (!mixins.includes(mixin)) {
30 | ctx.app.mixins = mixins.concat(mixin)
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/table/QTd.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QTd',
3 | props: {
4 | props: Object,
5 | autoWidth: Boolean
6 | },
7 | render (h) {
8 | if (!this.props) {
9 | return h('td', {
10 | 'class': { 'q-table-col-auto-width': this.autoWidth }
11 | }, this.$slots.default)
12 | }
13 |
14 | let col
15 | const name = this.$vnode.key
16 |
17 | if (name) {
18 | col = this.props.colsMap[name]
19 | if (!col) { return }
20 | }
21 | else {
22 | col = this.props.col
23 | }
24 |
25 | return h('td', {
26 | 'class': [col.__tdClass, {
27 | 'q-table-col-auto-width': this.autoWidth
28 | }]
29 | }, this.$slots.default)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/plugins/loading-bar.js:
--------------------------------------------------------------------------------
1 | import { isSSR } from './platform.js'
2 | import QAjaxBar from '../components/ajax-bar/QAjaxBar.js'
3 |
4 | export default {
5 | start () {},
6 | stop () {},
7 | increment () {},
8 |
9 | install ({ $q, Vue, cfg }) {
10 | if (isSSR) {
11 | $q.loadingBar = this
12 | return
13 | }
14 |
15 | const bar = $q.loadingBar = new Vue({
16 | render: h => h(QAjaxBar, {
17 | ref: 'bar',
18 | props: cfg.loadingBar
19 | })
20 | }).$mount().$refs.bar
21 |
22 | Object.assign(this, {
23 | start: bar.start,
24 | stop: bar.stop,
25 | increment: bar.increment
26 | })
27 |
28 | document.body.appendChild($q.loadingBar.$parent.$el)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/carousel/QCarouselControl.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCarouselControl',
3 | props: {
4 | position: {
5 | type: String,
6 | default: 'bottom-right'
7 | },
8 | offset: {
9 | type: Array,
10 | default: () => [18, 18]
11 | }
12 | },
13 | computed: {
14 | computedClass () {
15 | return `absolute-${this.position}`
16 | },
17 | computedStyle () {
18 | return {
19 | margin: `${this.offset[1]}px ${this.offset[0]}px`
20 | }
21 | }
22 | },
23 | render (h) {
24 | return h('div', {
25 | staticClass: 'q-carousel-control absolute',
26 | style: this.computedStyle,
27 | 'class': this.computedClass
28 | }, this.$slots.default)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/breadcrumbs/QBreadcrumbsEl.js:
--------------------------------------------------------------------------------
1 | import QIcon from '../icon/QIcon.js'
2 | import { routerLinkProps } from '../../utils/router-link.js'
3 |
4 | export default {
5 | name: 'QBreadcrumbsEl',
6 | mixins: [{ props: routerLinkProps }],
7 | props: {
8 | label: String,
9 | icon: String,
10 | color: String
11 | },
12 | render (h) {
13 | return h(this.to !== void 0 ? 'router-link' : 'span', {
14 | staticClass: 'q-link q-breadcrumbs-el flex inline items-center relative-position',
15 | props: this.to !== void 0 ? this.$props : null
16 | }, [
17 | this.icon ? h(QIcon, { staticClass: 'q-breacrumbs-el-icon q-mr-sm', props: { name: this.icon } }) : null,
18 | this.label
19 | ].concat(this.$slots.default))
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/utils/escape-key.js:
--------------------------------------------------------------------------------
1 | import Platform from '../plugins/platform.js'
2 |
3 | let handlers = []
4 |
5 | export default {
6 | __installed: false,
7 | __install () {
8 | this.__installed = true
9 | window.addEventListener('keyup', evt => {
10 | if (handlers.length === 0) {
11 | return
12 | }
13 |
14 | if (evt.which === 27 || evt.keyCode === 27) {
15 | handlers[handlers.length - 1]()
16 | }
17 | })
18 | },
19 |
20 | register (handler) {
21 | if (Platform.is.desktop) {
22 | if (!this.__installed) {
23 | this.__install()
24 | }
25 |
26 | handlers.push(handler)
27 | }
28 | },
29 |
30 | pop () {
31 | if (Platform.is.desktop) {
32 | handlers.pop()
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/dev/components/css/shadows.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Standard shadows
4 |
.shadow-{{ n }}
5 |
Shadows pointing up
6 |
.shadow-up-{{ n }}
7 |
Inset Shadow
8 |
.inset-shadow
9 |
10 |
11 |
12 |
19 |
--------------------------------------------------------------------------------
/src/components/spinner/QSpinner.mat.js:
--------------------------------------------------------------------------------
1 | import mixin from './spinner-mixin.js'
2 |
3 | export default {
4 | name: 'QSpinnerMat',
5 | mixins: [mixin],
6 | render (h) {
7 | return h('svg', {
8 | staticClass: 'q-spinner q-spinner-mat',
9 | class: this.classes,
10 | attrs: {
11 | 'width': this.size,
12 | 'height': this.size,
13 | 'viewBox': '25 25 50 50'
14 | }
15 | }, [
16 | h('circle', {
17 | staticClass: 'path',
18 | attrs: {
19 | 'cx': '50',
20 | 'cy': '50',
21 | 'r': '20',
22 | 'fill': 'none',
23 | 'stroke': 'currentColor',
24 | 'stroke-width': '3',
25 | 'stroke-miterlimit': '10'
26 | }
27 | })
28 | ])
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/dev/components/other/screen-plugin.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
lt-md
4 |
md
5 |
gt-md
6 |
7 | lt-md
8 | md
9 | gt-md
10 |
11 |
{{ $q.screen }}
12 |
13 |
14 |
15 |
32 |
--------------------------------------------------------------------------------
/dev/components/meta/layout_2.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Second Layout
7 | Running on Quasar v{{ $q.version }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
33 |
--------------------------------------------------------------------------------
/src/components/list/QItem.js:
--------------------------------------------------------------------------------
1 | import ItemMixin from '../../mixins/item.js'
2 |
3 | export default {
4 | name: 'QItem',
5 | mixins: [ ItemMixin ],
6 | props: {
7 | active: Boolean,
8 | link: Boolean
9 | },
10 | computed: {
11 | classes () {
12 | return [
13 | this.to !== void 0
14 | ? 'q-link'
15 | : {active: this.active},
16 | this.itemClasses
17 | ]
18 | }
19 | },
20 | render (h) {
21 | if (this.to !== void 0) {
22 | return h('router-link', {
23 | props: Object.assign({}, this.$props, { tag: 'a' }),
24 | 'class': this.classes
25 | }, this.$slots.default)
26 | }
27 |
28 | return h(
29 | this.tag,
30 | { 'class': this.classes },
31 | this.$slots.default
32 | )
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/inner-loading/QInnerLoading.js:
--------------------------------------------------------------------------------
1 | import QSpinner from '../spinner/QSpinner.js'
2 |
3 | export default {
4 | name: 'QInnerLoading',
5 | props: {
6 | dark: Boolean,
7 | visible: Boolean,
8 | size: {
9 | type: [String, Number],
10 | default: 42
11 | },
12 | color: String
13 | },
14 | render (h) {
15 | if (!this.visible) {
16 | return
17 | }
18 |
19 | return h(
20 | 'div',
21 | {
22 | staticClass: 'q-inner-loading animate-fade absolute-full column flex-center',
23 | 'class': { dark: this.dark }
24 | },
25 | this.$slots.default || [
26 | h(QSpinner, {
27 | props: {
28 | size: this.size,
29 | color: this.color
30 | }
31 | })
32 | ]
33 | )
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/dev/spa.index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Quasar Development
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/dev/components/meta/layout_1.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | First Layout
7 | Running on Quasar v{{ $q.version }}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
31 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "development": {
4 | "presets": [
5 | [
6 | "@babel/preset-env", {
7 | "modules": false,
8 | "loose": false,
9 | "useBuiltIns": "usage"
10 | }
11 | ],
12 | [
13 | "@babel/preset-stage-2", {
14 | "modules": false,
15 | "loose": false,
16 | "useBuiltIns": true,
17 | "decoratorsLegacy": true
18 | }
19 | ]
20 | ],
21 | "plugins": [
22 | [
23 | "@babel/transform-runtime", {
24 | "polyfill": false,
25 | "regenerator": false
26 | }
27 | ]
28 | ],
29 | "comments": false
30 | },
31 | "production": {
32 | "presets": ["es2015-rollup"],
33 | "comments": false
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/utils/is.js:
--------------------------------------------------------------------------------
1 | export function isPrintableChar (v) {
2 | return (v > 47 && v < 58) || // number keys
3 | v === 32 || v === 13 || // spacebar & return key(s) (if you want to allow carriage returns)
4 | (v > 64 && v < 91) || // letter keys
5 | (v > 95 && v < 112) || // numpad keys
6 | (v > 185 && v < 193) || // ;=,-./` (in order)
7 | (v > 218 && v < 223)
8 | }
9 |
10 | export function isObject (v) {
11 | return Object(v) === v
12 | }
13 |
14 | export function isDate (v) {
15 | return Object.prototype.toString.call(v) === '[object Date]'
16 | }
17 |
18 | export function isRegexp (v) {
19 | return Object.prototype.toString.call(v) === '[object RegExp]'
20 | }
21 |
22 | export function isNumber (v) {
23 | return typeof v === 'number' && isFinite(v)
24 | }
25 |
26 | export function isString (v) {
27 | return typeof v === 'string'
28 | }
29 |
--------------------------------------------------------------------------------
/src/utils/router-link.js:
--------------------------------------------------------------------------------
1 | import { isSSR } from '../plugins/platform.js'
2 |
3 | export const routerLinkEventName = 'qrouterlinkclick'
4 |
5 | let evt = null
6 |
7 | if (!isSSR) {
8 | try {
9 | evt = new Event(routerLinkEventName)
10 | }
11 | catch (e) {
12 | // IE doesn't support `new Event()`, so...`
13 | evt = document.createEvent('Event')
14 | evt.initEvent(routerLinkEventName, true, false)
15 | }
16 | }
17 |
18 | export const routerLinkProps = {
19 | to: [String, Object],
20 | exact: Boolean,
21 | append: Boolean,
22 | replace: Boolean,
23 | event: [String, Array],
24 | activeClass: String,
25 | exactActiveClass: String
26 | }
27 |
28 | export { evt as routerLinkEvent }
29 |
30 | export const RouterLinkMixin = {
31 | props: routerLinkProps,
32 | data () {
33 | return {
34 | routerLinkEventName
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/action-sheet/action-sheet.ios.styl:
--------------------------------------------------------------------------------
1 | .q-actionsheet
2 | border-radius $action-sheet-border-radius
3 | background $action-sheet-background
4 | max-width 95%
5 | margin-left auto
6 | margin-right auto
7 | margin-bottom 10px
8 | overflow hidden
9 |
10 | .q-actionsheet-title
11 | min-height 48px
12 | padding 0 16px
13 | color $faded
14 | color var(--q-color-faded)
15 | text-align center
16 |
17 | .q-actionsheet-grid
18 | padding 8px 16px
19 | .q-item-separator-component
20 | margin 18px 0
21 |
22 | .q-actionsheet-grid-item
23 | padding 8px 16px
24 | transition background .3s
25 | &:hover, &:focus
26 | background $action-sheet-hover-background
27 | outline 0
28 | i, img
29 | font-size 48px
30 | margin-bottom 4px
31 | .avatar
32 | width 48px
33 | height 48px
34 | span
35 | color $faded
36 | color var(--q-color-faded)
37 |
--------------------------------------------------------------------------------
/src/components/card/QCard.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCard',
3 | props: {
4 | square: Boolean,
5 | flat: Boolean,
6 | inline: Boolean,
7 | color: String,
8 | textColor: String
9 | },
10 | computed: {
11 | classes () {
12 | const cls = [{
13 | 'no-border-radius': this.square,
14 | 'no-shadow': this.flat,
15 | 'inline-block': this.inline
16 | }]
17 |
18 | if (this.color) {
19 | cls.push(`bg-${this.color}`)
20 | cls.push(`q-card-dark`)
21 | cls.push(`text-${this.textColor || 'white'}`)
22 | }
23 | else if (this.textColor) {
24 | cls.push(`text-${this.textColor}`)
25 | }
26 |
27 | return cls
28 | }
29 | },
30 | render (h) {
31 | return h('div', {
32 | staticClass: 'q-card',
33 | 'class': this.classes
34 | }, this.$slots.default)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/dev/components/new-layout/pages/b.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Page B
4 |
5 |
6 |
7 | Go to A
8 | Go to B
9 | Go to C
10 |
11 |
12 |
13 | Replace Go to A
14 | Replace Go to B
15 | Replace Go to C
16 |
17 |
18 |
19 |
32 |
--------------------------------------------------------------------------------
/dev/components/new-layout/pages/c.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Page C
4 |
5 |
6 |
7 | Go to A
8 | Go to B
9 | Go to C
10 |
11 |
12 |
13 | Replace Go to A
14 | Replace Go to B
15 | Replace Go to C
16 |
17 |
18 |
19 |
32 |
--------------------------------------------------------------------------------
/src/components/toolbar/QToolbar.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QToolbar',
3 | props: {
4 | color: {
5 | type: String,
6 | default: 'primary'
7 | },
8 | textColor: String,
9 | inverted: Boolean,
10 | glossy: Boolean
11 | },
12 | computed: {
13 | classes () {
14 | const cls = [ `q-toolbar-${this.inverted ? 'inverted' : 'normal'}` ]
15 |
16 | this.glossy && cls.push('glossy')
17 |
18 | if (this.inverted) {
19 | cls.push(`text-${this.textColor || this.color}`)
20 | }
21 | else {
22 | cls.push(`bg-${this.color}`)
23 | cls.push(`text-${this.textColor || 'white'}`)
24 | }
25 |
26 | return cls
27 | }
28 | },
29 | render (h) {
30 | return h('div', {
31 | staticClass: 'q-toolbar row no-wrap items-center relative-position',
32 | 'class': this.classes
33 | }, this.$slots.default)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/index.umd.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | import install from './install.js'
4 | import { version } from '../package.json'
5 |
6 | import * as components from './components.js'
7 | import * as directives from './directives.js'
8 | import * as plugins from './plugins.js'
9 | import * as utils from './utils.js'
10 | import i18n from './i18n.js'
11 | import icons from './icons.js'
12 |
13 | if (Vue === void 0) {
14 | console.error('[ Quasar ] Vue is required to run. Please add a script tag for it before loading Quasar.')
15 | }
16 | else {
17 | Vue.use({ install }, {
18 | components,
19 | directives,
20 | plugins,
21 | config: typeof window !== 'undefined'
22 | ? (window.quasarConfig || {})
23 | : {}
24 | })
25 | }
26 |
27 | export default {
28 | version,
29 | theme: process.env.THEME,
30 |
31 | i18n,
32 | icons,
33 | components,
34 | directives,
35 | plugins,
36 | utils
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/no-ssr/QNoSsr.js:
--------------------------------------------------------------------------------
1 | import CanRenderMixin from '../../mixins/can-render.js'
2 |
3 | export default {
4 | name: 'QNoSsr',
5 | mixins: [ CanRenderMixin ],
6 | props: {
7 | tag: {
8 | type: String,
9 | default: 'div'
10 | },
11 | placeholder: String
12 | },
13 | render (h) {
14 | if (this.canRender) {
15 | const slot = this.$slots.default
16 | return slot && slot.length > 1
17 | ? h(this.tag, slot)
18 | : (slot ? slot[0] : null)
19 | }
20 |
21 | if (this.$slots.placeholder) {
22 | const slot = this.$slots.placeholder
23 | return slot && slot.length > 1
24 | ? h(this.tag, { staticClass: 'q-no-ssr-placeholder' }, slot)
25 | : (slot ? slot[0] : null)
26 | }
27 |
28 | if (this.placeholder) {
29 | return h(this.tag, { staticClass: 'q-no-ssr-placeholder' }, [
30 | this.placeholder
31 | ])
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/directives/close-overlay.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'close-overlay',
3 | bind (el, binding, vnode) {
4 | const
5 | handler = ev => {
6 | let vm = vnode.componentInstance
7 | while ((vm = vm.$parent)) {
8 | const name = vm.$options.name
9 | if (name === 'QPopover' || name === 'QModal') {
10 | vm.hide(ev)
11 | break
12 | }
13 | }
14 | },
15 | handlerKey = ev => {
16 | if (ev.keyCode === 13) {
17 | handler(ev)
18 | }
19 | }
20 | el.__qclose = { handler, handlerKey }
21 | el.addEventListener('click', handler)
22 | el.addEventListener('keyup', handlerKey)
23 | },
24 | unbind (el) {
25 | const ctx = el.__qclose
26 | if (!ctx) { return }
27 | el.removeEventListener('click', ctx.handler)
28 | el.removeEventListener('keyup', ctx.handlerKey)
29 | delete el.__qclose
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/tab/QTab.js:
--------------------------------------------------------------------------------
1 | import TabMixin from './tab-mixin.js'
2 |
3 | export default {
4 | name: 'QTab',
5 | mixins: [TabMixin],
6 | props: {
7 | default: Boolean
8 | },
9 | methods: {
10 | select () {
11 | this.$emit('click', this.name)
12 | if (!this.disable) {
13 | this.selectTab(this.name)
14 | }
15 | }
16 | },
17 | mounted () {
18 | if (this.default && !this.disable) {
19 | this.select()
20 | }
21 | },
22 | render (h) {
23 | return h('div', {
24 | staticClass: 'q-tab column flex-center relative-position',
25 | 'class': this.classes,
26 | attrs: { 'data-tab-name': this.name },
27 | on: {
28 | click: this.select,
29 | keyup: e => e.keyCode === 13 && this.select(e)
30 | },
31 | directives: process.env.THEME === 'mat'
32 | ? [{ name: 'ripple' }]
33 | : null
34 | }, this.__getTabContent(h))
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/dev/ssr.index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ Q_HEAD_TAGS }}
5 |
6 |
7 |
8 |
9 |
10 |
11 | Quasar Development
12 |
13 |
14 |
15 |
16 |
17 | {{ Q_BODY_TAGS }}
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.stylintrc:
--------------------------------------------------------------------------------
1 | {
2 | "blocks": "never",
3 | "brackets": "never",
4 | "colons": "never",
5 | "colors": "always",
6 | "commaSpace": "always",
7 | "commentSpace": "always",
8 | "cssLiteral": "never",
9 | "depthLimit": false,
10 | "duplicates": true,
11 | "efficient": "always",
12 | "extendPref": false,
13 | "globalDupe": true,
14 | "indentPref": 2,
15 | "leadingZero": "never",
16 | "maxErrors": false,
17 | "maxWarnings": false,
18 | "mixed": false,
19 | "namingConvention": false,
20 | "namingConventionStrict": false,
21 | "none": "never",
22 | "noImportant": false,
23 | "parenSpace": "never",
24 | "placeholder": false,
25 | "prefixVarsWithDollar": "always",
26 | "quotePref": "single",
27 | "semicolons": "never",
28 | "sortOrder": false,
29 | "stackedProperties": "never",
30 | "trailingWhitespace": "never",
31 | "universal": "never",
32 | "valid": true,
33 | "zeroUnits": "never",
34 | "zIndexNormalize": false
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/collapsible/collapsible.ios.styl:
--------------------------------------------------------------------------------
1 | .q-collapsible-sub-item
2 | padding $collapsible-padding
3 | &.indent
4 | padding-left $collapsible-menu-left-padding
5 | padding-right 0
6 |
7 | .q-card
8 | margin-bottom 0
9 |
10 | .q-collapsible.{$router-link-active} > .q-item
11 | background $collapsible-active-color
12 |
13 | .q-collapsible
14 | transition padding .5s
15 |
16 | .q-collapsible-popup-closed
17 | padding 0 15px
18 | .q-collapsible-inner
19 | border 1px solid $item-separator-color
20 | & + &
21 | .q-collapsible-inner
22 | border-top 0
23 |
24 | .q-collapsible-popup-opened
25 | padding 15px 0
26 | .q-collapsible-inner
27 | box-shadow $shadow-2
28 | & + &, &:first-child
29 | padding-top 0
30 | &:last-child
31 | padding-bottom 0
32 |
33 | .q-collapsible-cursor-pointer > .q-collapsible-inner > .q-item
34 | cursor pointer
35 |
36 | .q-collapsible-toggle-icon
37 | border-radius 50%
38 | width 1em
39 | text-align center
40 |
--------------------------------------------------------------------------------
/src/components/collapsible/collapsible.mat.styl:
--------------------------------------------------------------------------------
1 | .q-collapsible-sub-item
2 | padding $collapsible-padding
3 | &.indent
4 | padding-left $collapsible-menu-left-padding
5 | padding-right 0
6 |
7 | .q-card
8 | margin-bottom 0
9 |
10 | .q-collapsible.{$router-link-active} > .q-item
11 | background $collapsible-active-color
12 |
13 | .q-collapsible
14 | transition padding .5s
15 |
16 | .q-collapsible-popup-closed
17 | padding 0 15px
18 | .q-collapsible-inner
19 | border 1px solid $item-separator-color
20 | & + &
21 | .q-collapsible-inner
22 | border-top 0
23 |
24 | .q-collapsible-popup-opened
25 | padding 15px 0
26 | .q-collapsible-inner
27 | box-shadow $shadow-2
28 | & + &, &:first-child
29 | padding-top 0
30 | &:last-child
31 | padding-bottom 0
32 |
33 | .q-collapsible-cursor-pointer > .q-collapsible-inner > .q-item
34 | cursor pointer
35 |
36 | .q-collapsible-toggle-icon
37 | border-radius 50%
38 | width 1em
39 | text-align center
40 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | import animate from './utils/animate.js'
2 | import clone from './utils/clone.js'
3 | import colors from './utils/colors.js'
4 | import date from './utils/date.js'
5 | import debounce from './utils/debounce.js'
6 | import dom from './utils/dom.js'
7 | import easing from './utils/easing.js'
8 | import event from './utils/event.js'
9 | import extend from './utils/extend.js'
10 | import filter from './utils/filter.js'
11 | import format from './utils/format.js'
12 | import frameDebounce from './utils/frame-debounce.js'
13 | import openURL from './utils/open-url.js'
14 | import scroll from './utils/scroll.js'
15 | import throttle from './utils/throttle.js'
16 | import uid from './utils/uid.js'
17 |
18 | function noop () {}
19 |
20 | export {
21 | animate,
22 | clone,
23 | colors,
24 | date,
25 | debounce,
26 | dom,
27 | easing,
28 | event,
29 | extend,
30 | filter,
31 | format,
32 | frameDebounce,
33 | noop,
34 | openURL,
35 | scroll,
36 | throttle,
37 | uid
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/table/table-column-selection.js:
--------------------------------------------------------------------------------
1 | export default {
2 | props: {
3 | visibleColumns: Array
4 | },
5 | computed: {
6 | computedCols () {
7 | let { sortBy, descending } = this.computedPagination
8 |
9 | const cols = this.visibleColumns
10 | ? this.columns.filter(col => col.required || this.visibleColumns.includes(col.name))
11 | : this.columns
12 |
13 | return cols.map(col => {
14 | col.align = col.align || 'right'
15 | col.__iconClass = `q-table-sort-icon q-table-sort-icon-${col.align}`
16 | col.__thClass = `text-${col.align}${col.sortable ? ' sortable' : ''}${col.name === sortBy ? ` sorted ${descending ? 'sort-desc' : ''}` : ''}`
17 | col.__tdClass = `text-${col.align}`
18 | return col
19 | })
20 | },
21 | computedColsMap () {
22 | const names = {}
23 | this.computedCols.forEach(col => {
24 | names[col.name] = col
25 | })
26 | return names
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/plugins.js:
--------------------------------------------------------------------------------
1 | import ActionSheet from './plugins/action-sheet.js'
2 | import AddressbarColor from './plugins/addressbar-color.js'
3 | import AppFullscreen from './plugins/app-fullscreen.js'
4 | import AppVisibility from './plugins/app-visibility.js'
5 | import Cookies from './plugins/cookies.js'
6 | import Dialog from './plugins/dialog.js'
7 | import LoadingBar from './plugins/loading-bar.js'
8 | import Loading from './plugins/loading.js'
9 | import Meta from './plugins/meta.js'
10 | import Notify from './plugins/notify.js'
11 | import Platform from './plugins/platform.js'
12 | import Screen from './plugins/screen.js'
13 | import LocalStorage from './plugins/local-storage.js'
14 | import SessionStorage from './plugins/session-storage.js'
15 |
16 | export {
17 | ActionSheet,
18 | AddressbarColor,
19 | AppFullscreen,
20 | AppVisibility,
21 | Cookies,
22 | Dialog,
23 | LoadingBar,
24 | Loading,
25 | Meta,
26 | Notify,
27 | Platform,
28 | Screen,
29 | LocalStorage,
30 | SessionStorage
31 | }
32 |
--------------------------------------------------------------------------------
/dev/components/meta/pages/third.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Page third
4 | Layout 1
5 |
6 |
7 |
8 |
9 |
10 | Layout 2
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{ __qMeta }}
18 |
19 |
20 |
21 |
34 |
--------------------------------------------------------------------------------
/src/components/fab/QFabAction.js:
--------------------------------------------------------------------------------
1 | import QBtn from '../btn/QBtn.js'
2 | import FabMixin from './fab-mixin.js'
3 |
4 | export default {
5 | name: 'QFabAction',
6 | mixins: [FabMixin],
7 | props: {
8 | icon: {
9 | type: String,
10 | required: true
11 | }
12 | },
13 | inject: {
14 | __qFabClose: {
15 | default () {
16 | console.error('QFabAction needs to be child of QFab')
17 | }
18 | }
19 | },
20 | methods: {
21 | click (e) {
22 | this.__qFabClose().then(() => {
23 | this.$emit('click', e)
24 | })
25 | }
26 | },
27 | render (h) {
28 | return h(QBtn, {
29 | props: {
30 | fabMini: true,
31 | outline: this.outline,
32 | push: this.push,
33 | flat: this.flat,
34 | color: this.color,
35 | textColor: this.textColor,
36 | glossy: this.glossy,
37 | icon: this.icon
38 | },
39 | on: {
40 | click: this.click
41 | }
42 | }, this.$slots.default)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/jumbotron/QJumbotron.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QJumbotron',
3 | props: {
4 | dark: Boolean,
5 | tag: {
6 | type: String,
7 | default: 'div'
8 | },
9 | imgSrc: String,
10 | gradient: String
11 | },
12 | computed: {
13 | gradientType () {
14 | if (this.gradient) {
15 | return this.gradient.indexOf('circle') > -1
16 | ? 'radial'
17 | : 'linear'
18 | }
19 | },
20 | computedStyle () {
21 | if (this.imgSrc) {
22 | return {
23 | 'background-image': `url(${this.imgSrc})`
24 | }
25 | }
26 | if (this.gradientType) {
27 | return {
28 | background: `${this.gradientType}-gradient(${this.gradient})`
29 | }
30 | }
31 | }
32 | },
33 | render (h) {
34 | return h(this.tag, {
35 | staticClass: 'q-jumbotron',
36 | style: this.computedStyle,
37 | 'class': {
38 | 'q-jumbotron-dark': this.dark
39 | }
40 | }, this.$slots.default)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/dev/components/other/platform-detection.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Based on the device you are using to view this, Quasar detects the following:
6 |
7 |
8 |
9 |
10 |
11 | Property
12 | Value
13 |
14 |
15 |
16 |
17 |
18 | {{ prop }}
19 | {{ value }}
20 |
21 |
22 |
23 |
24 |
25 | Your device {{ touch }} touch capability.
26 |
27 |
28 |
29 |
30 |
31 |
40 |
--------------------------------------------------------------------------------
/src/components/list/QItemMain.js:
--------------------------------------------------------------------------------
1 | import { textStyle } from '../../mixins/item.js'
2 |
3 | function text (h, name, val, n) {
4 | n = parseInt(n, 10)
5 | return h('div', {
6 | staticClass: `q-item-${name}${n === 1 ? ' ellipsis' : ''}`,
7 | style: textStyle(n),
8 | domProps: {
9 | innerHTML: val
10 | }
11 | })
12 | }
13 |
14 | export default {
15 | name: 'QItemMain',
16 | props: {
17 | label: String,
18 | labelLines: [String, Number],
19 | sublabel: String,
20 | sublabelLines: [String, Number],
21 | inset: Boolean,
22 | tag: {
23 | type: String,
24 | default: 'div'
25 | }
26 | },
27 | render (h) {
28 | return h(this.tag, {
29 | staticClass: 'q-item-main q-item-section',
30 | 'class': {
31 | 'q-item-main-inset': this.inset
32 | }
33 | }, [
34 | this.label ? text(h, 'label', this.label, this.labelLines) : null,
35 | this.sublabel ? text(h, 'sublabel', this.sublabel, this.sublabelLines) : null,
36 | this.$slots.default
37 | ])
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/table/QTableColumns.js:
--------------------------------------------------------------------------------
1 | import QSelect from '../select/QSelect.js'
2 |
3 | export default {
4 | name: 'QTableColumns',
5 | props: {
6 | value: {
7 | type: Array,
8 | required: true
9 | },
10 | label: String,
11 | columns: {
12 | type: Array,
13 | required: true
14 | },
15 | color: String
16 | },
17 | computed: {
18 | computedOptions () {
19 | return this.columns.filter(col => !col.required).map(col => ({
20 | value: col.name,
21 | label: col.label
22 | }))
23 | }
24 | },
25 | render (h) {
26 | return h(QSelect, {
27 | props: {
28 | multiple: true,
29 | toggle: true,
30 | value: this.value,
31 | options: this.computedOptions,
32 | displayValue: this.label || this.$q.i18n.table.columns,
33 | color: this.color,
34 | hideUnderline: true
35 | },
36 | on: {
37 | input: v => { this.$emit('input', v) },
38 | change: v => { this.$emit('change', v) }
39 | }
40 | })
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/carousel/QCarouselSlide.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QCarouselSlide',
3 | inject: {
4 | carousel: {
5 | default () {
6 | console.error('QCarouselSlide needs to be child of QCarousel')
7 | }
8 | }
9 | },
10 | props: {
11 | imgSrc: String
12 | },
13 | computed: {
14 | computedStyle () {
15 | const style = {}
16 | if (this.imgSrc) {
17 | style.backgroundImage = `url(${this.imgSrc})`
18 | style.backgroundSize = `cover`
19 | style.backgroundPosition = `50%`
20 | }
21 | if (!this.carousel.inFullscreen && this.carousel.height) {
22 | style.maxHeight = this.carousel.height
23 | }
24 | return style
25 | }
26 | },
27 | render (h) {
28 | return h('div', {
29 | staticClass: 'q-carousel-slide relative-position scroll',
30 | style: this.computedStyle
31 | }, this.$slots.default)
32 | },
33 | created () {
34 | this.carousel.__registerSlide()
35 | },
36 | beforeDestroy () {
37 | this.carousel.__unregisterSlide()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/toggle/toggle.mat.styl:
--------------------------------------------------------------------------------
1 | $toggle-width = 40px
2 | $toggle-height = 21px
3 | $toggle-handle-size = $toggle-height
4 | $toggle-base-height = round($toggle-handle-size / 1.7)
5 |
6 | .q-toggle-base
7 | transition all .45s cubic-bezier(.23, 1, .32, 1)
8 | width 100%
9 | height $toggle-base-height
10 | border-radius 30px
11 | background currentColor
12 | opacity .5
13 |
14 | .q-toggle-handle
15 | background rgb(245, 245, 245)
16 | transition all 450ms cubic-bezier(.23, 1, .32, 1)
17 | box-shadow $shadow-1
18 | border-radius 50%
19 | position absolute
20 | top 0
21 | left 0
22 | width $toggle-handle-size
23 | height $toggle-handle-size
24 | line-height $toggle-handle-size
25 |
26 | .q-toggle .q-option-inner
27 | height $toggle-height
28 | width $toggle-width
29 | min-width $toggle-width
30 | padding round(($toggle-height - $toggle-base-height) / 2) 0
31 | &.active
32 | .q-toggle-handle
33 | background currentColor
34 | left ($toggle-width - $toggle-handle-size)
35 | .q-toggle-icon
36 | color white
37 |
--------------------------------------------------------------------------------
/src/history.js:
--------------------------------------------------------------------------------
1 | import { isSSR } from './plugins/platform.js'
2 |
3 | export default {
4 | __history: [],
5 | add: () => {},
6 | remove: () => {},
7 |
8 | install ($q, cfg) {
9 | if (isSSR || !$q.platform.is.cordova) {
10 | return
11 | }
12 |
13 | this.add = definition => {
14 | this.__history.push(definition)
15 | }
16 | this.remove = definition => {
17 | const index = this.__history.indexOf(definition)
18 | if (index >= 0) {
19 | this.__history.splice(index, 1)
20 | }
21 | }
22 |
23 | const exit = cfg.cordova === void 0 || cfg.cordova.backButtonExit !== false
24 |
25 | document.addEventListener('deviceready', () => {
26 | document.addEventListener('backbutton', () => {
27 | if (this.__history.length) {
28 | this.__history.pop().handler()
29 | }
30 | else if (exit && window.location.hash === '#/') {
31 | navigator.app.exitApp()
32 | }
33 | else {
34 | window.history.back()
35 | }
36 | }, false)
37 | })
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/plugins/app-visibility.js:
--------------------------------------------------------------------------------
1 | import { isSSR } from './platform.js'
2 |
3 | export default {
4 | appVisible: false,
5 |
6 | install ({ $q, Vue }) {
7 | if (isSSR) {
8 | this.appVisible = $q.appVisible = true
9 | return
10 | }
11 |
12 | let prop, evt
13 |
14 | if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
15 | prop = 'hidden'
16 | evt = 'visibilitychange'
17 | }
18 | else if (typeof document.msHidden !== 'undefined') {
19 | prop = 'msHidden'
20 | evt = 'msvisibilitychange'
21 | }
22 | else if (typeof document.webkitHidden !== 'undefined') {
23 | prop = 'webkitHidden'
24 | evt = 'webkitvisibilitychange'
25 | }
26 |
27 | const update = () => {
28 | this.appVisible = $q.appVisible = !document[prop]
29 | }
30 |
31 | update()
32 |
33 | if (evt && typeof document[prop] !== 'undefined') {
34 | Vue.util.defineReactive($q, 'appVisible', this.appVisible)
35 | document.addEventListener(evt, update, false)
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/editor/editor.ios.styl:
--------------------------------------------------------------------------------
1 | .q-editor
2 | border $editor-border
3 | &.disabled
4 | border-style dashed
5 | &.fullscreen
6 | border 0 !important
7 |
8 | .q-editor-content
9 | outline 0
10 | padding $editor-content-padding
11 | min-height $editor-content-min-height
12 | background white
13 |
14 | hr
15 | border 0
16 | outline 0
17 | margin 1px
18 | height 1px
19 | background $editor-hr-color
20 |
21 | .q-editor-toolbar-padding
22 | padding $editor-toolbar-padding
23 |
24 | .q-editor-toolbar
25 | border-bottom $editor-border
26 | background $grey-4
27 | min-height 37px
28 | .q-btn-group
29 | box-shadow none
30 | .q-btn-group + .q-btn-group
31 | margin-left $editor-button-gutter
32 | .q-editor-toolbar-separator
33 | .q-btn-group + .q-btn-group
34 | padding-left $editor-button-gutter
35 | &:before
36 | content ''
37 | position absolute
38 | left 0
39 | top 0
40 | bottom 0
41 | height 100%
42 | width 1px
43 | background $editor-border-color
44 |
45 | .q-editor-input input
46 | color inherit
47 |
--------------------------------------------------------------------------------
/src/components/editor/editor.mat.styl:
--------------------------------------------------------------------------------
1 | .q-editor
2 | border $editor-border
3 | &.disabled
4 | border-style dashed
5 | &.fullscreen
6 | border 0 !important
7 |
8 | .q-editor-content
9 | outline 0
10 | padding $editor-content-padding
11 | min-height $editor-content-min-height
12 | background white
13 |
14 | hr
15 | border 0
16 | outline 0
17 | margin 1px
18 | height 1px
19 | background $editor-hr-color
20 |
21 | .q-editor-toolbar-padding
22 | padding $editor-toolbar-padding
23 |
24 | .q-editor-toolbar
25 | border-bottom $editor-border
26 | background $grey-4
27 | min-height 37px
28 | .q-btn-group
29 | box-shadow none
30 | .q-btn-group + .q-btn-group
31 | margin-left $editor-button-gutter
32 | .q-editor-toolbar-separator
33 | .q-btn-group + .q-btn-group
34 | padding-left $editor-button-gutter
35 | &:before
36 | content ''
37 | position absolute
38 | left 0
39 | top 0
40 | bottom 0
41 | height 100%
42 | width 1px
43 | background $editor-border-color
44 |
45 | .q-editor-input input
46 | color inherit
47 |
--------------------------------------------------------------------------------
/dev/components/css/flex-test.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
XS ({{ first }} )
4 |
SM ({{ second }} )
5 |
MD ({{ last }} )
6 |
{{ conf }}
7 |
8 |
First
9 |
Second
10 |
Last
11 |
12 |
13 |
14 |
15 |
38 |
39 |
48 |
--------------------------------------------------------------------------------
/src/components/list/QList.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QList',
3 | props: {
4 | noBorder: Boolean,
5 | dark: Boolean,
6 | dense: Boolean,
7 | sparse: Boolean,
8 | striped: Boolean,
9 | stripedOdd: Boolean,
10 | separator: Boolean,
11 | insetSeparator: Boolean,
12 | multiline: Boolean,
13 | highlight: Boolean,
14 | link: Boolean
15 | },
16 | computed: {
17 | classes () {
18 | return {
19 | 'no-border': this.noBorder,
20 | 'q-list-dark': this.dark,
21 | 'q-list-dense': this.dense,
22 | 'q-list-sparse': this.sparse,
23 | 'q-list-striped': this.striped,
24 | 'q-list-striped-odd': this.stripedOdd,
25 | 'q-list-separator': this.separator,
26 | 'q-list-inset-separator': this.insetSeparator,
27 | 'q-list-multiline': this.multiline,
28 | 'q-list-highlight': this.highlight,
29 | 'q-list-link': this.link
30 | }
31 | }
32 | },
33 | render (h) {
34 | return h('div', {
35 | staticClass: 'q-list',
36 | 'class': this.classes
37 | }, this.$slots.default)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/utils/modal-fn.js:
--------------------------------------------------------------------------------
1 | import { isSSR } from '../plugins/platform.js'
2 |
3 | export default function (Component, Vue) {
4 | return ({ className, ...props }, resolver) => {
5 | return new Promise((resolve, reject) => {
6 | if (isSSR) { return resolve() }
7 |
8 | const node = document.createElement('div')
9 | document.body.appendChild(node)
10 |
11 | const
12 | ok = data => {
13 | resolve(data)
14 | vm.$destroy()
15 | },
16 | cancel = reason => {
17 | reject(reason || new Error())
18 | vm.$destroy()
19 | }
20 |
21 | const vm = new Vue({
22 | el: node,
23 | data () {
24 | return { props }
25 | },
26 | render: h => h(Component, {
27 | ref: 'modal',
28 | props,
29 | 'class': className,
30 | on: {
31 | ok,
32 | cancel
33 | }
34 | }),
35 | mounted () {
36 | this.$refs.modal.show()
37 | }
38 | })
39 |
40 | resolver && resolver.then(ok, cancel)
41 | })
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/layout/QPageContainer.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QPageContainer',
3 | inject: {
4 | layout: {
5 | default () {
6 | console.error('QPageContainer needs to be child of QLayout')
7 | }
8 | }
9 | },
10 | provide: {
11 | pageContainer: true
12 | },
13 | computed: {
14 | style () {
15 | const css = {}
16 |
17 | if (this.layout.header.space) {
18 | css.paddingTop = `${this.layout.header.size}px`
19 | }
20 | if (this.layout.right.space) {
21 | css[`padding${this.$q.i18n.rtl ? 'Left' : 'Right'}`] = `${this.layout.right.size}px`
22 | }
23 | if (this.layout.footer.space) {
24 | css.paddingBottom = `${this.layout.footer.size}px`
25 | }
26 | if (this.layout.left.space) {
27 | css[`padding${this.$q.i18n.rtl ? 'Right' : 'Left'}`] = `${this.layout.left.size}px`
28 | }
29 |
30 | return css
31 | }
32 | },
33 | render (h) {
34 | return h('div', {
35 | staticClass: 'q-layout-page-container q-layout-transition',
36 | style: this.style
37 | }, this.$slots.default)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/observables/QWindowResizeObservable.js:
--------------------------------------------------------------------------------
1 | import { listenOpts } from '../../utils/event.js'
2 | import { onSSR, fromSSR } from '../../plugins/platform.js'
3 |
4 | export default {
5 | name: 'QWindowResizeObservable',
6 | props: {
7 | debounce: {
8 | type: Number,
9 | default: 80
10 | }
11 | },
12 | render () {},
13 | methods: {
14 | trigger () {
15 | if (this.debounce === 0) {
16 | this.emit()
17 | }
18 | else if (!this.timer) {
19 | this.timer = setTimeout(this.emit, this.debounce)
20 | }
21 | },
22 | emit (ssr) {
23 | this.timer = null
24 | this.$emit('resize', {
25 | height: ssr ? 0 : window.innerHeight,
26 | width: ssr ? 0 : window.innerWidth
27 | })
28 | }
29 | },
30 | created () {
31 | this.emit(onSSR)
32 | },
33 | mounted () {
34 | fromSSR && this.emit()
35 | window.addEventListener('resize', this.trigger, listenOpts.passive)
36 | },
37 | beforeDestroy () {
38 | clearTimeout(this.timer)
39 | window.removeEventListener('resize', this.trigger, listenOpts.passive)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Razvan Stoenescu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dev/components/components/back-to-top.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Scroll down
5 |
6 |
7 | A circular button is set to appear after scrolling 500px.
8 |
9 | After another 500px another element will appear on the left.
10 |
11 |
12 |
20 |
21 |
25 | Back to top
26 |
27 |
28 |
Keep scrolling...
29 |
30 |
31 |
32 |
42 |
--------------------------------------------------------------------------------
/src/components/layout/QPage.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QPage',
3 | inject: {
4 | pageContainer: {
5 | default () {
6 | console.error('QPage needs to be child of QPageContainer')
7 | }
8 | },
9 | layout: {}
10 | },
11 | props: {
12 | padding: Boolean,
13 | styleFn: Function
14 | },
15 | computed: {
16 | style () {
17 | const offset =
18 | (this.layout.header.space ? this.layout.header.size : 0) +
19 | (this.layout.footer.space ? this.layout.footer.size : 0)
20 |
21 | if (typeof this.styleFn === 'function') {
22 | return this.styleFn(offset)
23 | }
24 |
25 | const minHeight = this.layout.container
26 | ? (this.layout.containerHeight - offset) + 'px'
27 | : (offset ? `calc(100vh - ${offset}px)` : `100vh`)
28 |
29 | return { minHeight }
30 | },
31 | classes () {
32 | if (this.padding) {
33 | return 'layout-padding'
34 | }
35 | }
36 | },
37 | render (h) {
38 | return h('main', {
39 | staticClass: 'q-layout-page',
40 | style: this.style,
41 | 'class': this.classes
42 | }, this.$slots.default)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/dev/app.entry-server.js:
--------------------------------------------------------------------------------
1 | import { createApp } from './app'
2 |
3 | export default ssrContext => {
4 | // since there could potentially be asynchronous route hooks or components,
5 | // we will be returning a Promise so that the server can wait until
6 | // everything is ready before rendering.
7 |
8 | return new Promise((resolve, reject) => {
9 | const { app, router } = createApp(ssrContext)
10 |
11 | const { fullPath } = router.resolve(ssrContext.url).route
12 |
13 | if (fullPath !== ssrContext.url) {
14 | return reject({ url: fullPath })
15 | }
16 |
17 | // set server-side router's location
18 | router.push(ssrContext.url)
19 |
20 | // wait until router has resolved possible async components and hooks
21 | router.onReady(() => {
22 | const matchedComponents = router.getMatchedComponents()
23 | // no matched routes, reject with 404
24 | if (!matchedComponents.length) {
25 | return reject({ code: 404 })
26 | }
27 |
28 | // the Promise should resolve to the app instance so it can be rendered
29 | ssrContext.$getMetaHTML = app.$getMetaHTML(app)
30 | resolve(app)
31 | }, reject)
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/src/directives/go-back.js:
--------------------------------------------------------------------------------
1 | import Platform from '../plugins/platform.js'
2 |
3 | export default {
4 | name: 'go-back',
5 | bind (el, { value, modifiers }, vnode) {
6 | let ctx = { value, position: window.history.length - 1, single: modifiers.single }
7 |
8 | if (Platform.is.cordova) {
9 | ctx.goBack = () => {
10 | vnode.context.$router.go(ctx.single ? -1 : ctx.position - window.history.length)
11 | }
12 | }
13 | else {
14 | ctx.goBack = () => {
15 | vnode.context.$router.replace(ctx.value)
16 | }
17 | }
18 | ctx.goBackKey = ev => {
19 | if (ev.keyCode === 13) {
20 | ctx.goBack(ev)
21 | }
22 | }
23 |
24 | el.__qgoback = ctx
25 | el.addEventListener('click', ctx.goBack)
26 | el.addEventListener('keyup', ctx.goBackKey)
27 | },
28 | update (el, binding) {
29 | if (binding.oldValue !== binding.value) {
30 | el.__qgoback.value = binding.value
31 | }
32 | },
33 | unbind (el) {
34 | const ctx = el.__qgoback
35 | if (!ctx) { return }
36 | el.removeEventListener('click', ctx.goBack)
37 | el.removeEventListener('keyup', ctx.goBackKey)
38 | delete el.__qgoback
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/utils/format.js:
--------------------------------------------------------------------------------
1 | const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB']
2 |
3 | export function humanStorageSize (bytes) {
4 | let u = 0
5 |
6 | while (parseInt(bytes, 10) >= 1024 && u < units.length - 1) {
7 | bytes /= 1024
8 | ++u
9 | }
10 |
11 | return `${bytes.toFixed(1)} ${units[u]}`
12 | }
13 |
14 | export function capitalize (str) {
15 | return str.charAt(0).toUpperCase() + str.slice(1)
16 | }
17 |
18 | export function between (v, min, max) {
19 | if (max <= min) {
20 | return min
21 | }
22 | return Math.min(max, Math.max(min, v))
23 | }
24 |
25 | export function normalizeToInterval (v, min, max) {
26 | if (max <= min) {
27 | return min
28 | }
29 |
30 | const size = (max - min + 1)
31 |
32 | let index = min + (v - min) % size
33 | if (index < min) {
34 | index = size + index
35 | }
36 |
37 | return index === 0 ? 0 : index // fix for (-a % a) => -0
38 | }
39 |
40 | export function pad (v, length = 2, char = '0') {
41 | let val = '' + v
42 | return val.length >= length
43 | ? val
44 | : new Array(length - val.length + 1).join(char) + val
45 | }
46 |
47 | export default {
48 | humanStorageSize,
49 | capitalize,
50 | between,
51 | normalizeToInterval,
52 | pad
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/table/QTh.js:
--------------------------------------------------------------------------------
1 | import QIcon from '../icon/QIcon.js'
2 |
3 | export default {
4 | name: 'QTh',
5 | props: {
6 | props: Object,
7 | autoWidth: Boolean
8 | },
9 | render (h) {
10 | if (!this.props) {
11 | return h('td', {
12 | 'class': { 'q-table-col-auto-width': this.autoWidth }
13 | }, this.$slots.default)
14 | }
15 |
16 | let col
17 | const
18 | name = this.$vnode.key,
19 | child = [].concat(this.$slots.default)
20 |
21 | if (name) {
22 | col = this.props.colsMap[name]
23 | if (!col) { return }
24 | }
25 | else {
26 | col = this.props.col
27 | }
28 |
29 | if (col.sortable) {
30 | const action = col.align === 'right'
31 | ? 'unshift'
32 | : 'push'
33 |
34 | child[action](
35 | h(QIcon, {
36 | props: { name: this.$q.icon.table.arrowUp },
37 | staticClass: col.__iconClass
38 | })
39 | )
40 | }
41 |
42 | return h('th', {
43 | 'class': [col.__thClass, {
44 | 'q-table-col-auto-width': this.autoWidth
45 | }],
46 | on: col.sortable
47 | ? { click: () => { this.props.sort(col) } }
48 | : null
49 | }, child)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/dev/components/meta/pages/second.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Page second
4 | Layout 1
5 |
6 |
7 |
8 |
9 |
10 | Layout 2
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{ __qMeta }}
18 |
19 |
20 |
21 |
23 |
24 |
44 |
--------------------------------------------------------------------------------
/src/components/tab/QTabPane.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'QTabPane',
3 | inject: {
4 | data: {
5 | default () {
6 | console.error('QTabPane needs to be child of QTabs')
7 | }
8 | }
9 | },
10 | props: {
11 | name: {
12 | type: String,
13 | required: true
14 | },
15 | keepAlive: Boolean
16 | },
17 | data () {
18 | return {
19 | shown: false
20 | }
21 | },
22 | computed: {
23 | active () {
24 | return this.data.tabName === this.name
25 | },
26 | classes () {
27 | return {
28 | hidden: !this.active,
29 | 'animate-fade-left': this.data.direction === 'left',
30 | 'animate-fade-right': this.data.direction === 'right'
31 | }
32 | }
33 | },
34 | render (h) {
35 | const node = h(
36 | 'div',
37 | {
38 | staticClass: 'q-tab-pane',
39 | 'class': this.classes
40 | },
41 | this.$slots.default
42 | )
43 |
44 | if (this.keepAlive) {
45 | if (!this.shown && !this.active) {
46 | return
47 | }
48 | this.shown = true
49 | return node
50 | }
51 | else {
52 | this.shown = this.active
53 | if (this.active) {
54 | return node
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/components/spinner/QSpinnerInfinity.js:
--------------------------------------------------------------------------------
1 | import mixin from './spinner-mixin.js'
2 |
3 | export default {
4 | name: 'QSpinnerInfinity',
5 | mixins: [mixin],
6 | render (h) {
7 | return h('svg', {
8 | staticClass: 'q-spinner',
9 | class: this.classes,
10 | attrs: {
11 | 'width': this.size,
12 | 'height': this.size,
13 | 'viewBox': '0 0 100 100',
14 | 'preserveAspectRatio': 'xMidYMid'
15 | }
16 | }, [
17 | h('path', {
18 | attrs: {
19 | 'd': 'M24.3,30C11.4,30,5,43.3,5,50s6.4,20,19.3,20c19.3,0,32.1-40,51.4-40C88.6,30,95,43.3,95,50s-6.4,20-19.3,20C56.4,70,43.6,30,24.3,30z',
20 | 'fill': 'none',
21 | 'stroke': 'currentColor',
22 | 'stroke-width': '8',
23 | 'stroke-dasharray': '10.691205342610678 10.691205342610678',
24 | 'stroke-dashoffset': '0'
25 | }
26 | }, [
27 | h('animate', {
28 | attrs: {
29 | 'attributeName': 'stroke-dashoffset',
30 | 'from': '0',
31 | 'to': '21.382410685221355',
32 | 'begin': '0',
33 | 'dur': '2s',
34 | 'repeatCount': 'indefinite',
35 | 'fill': 'freeze'
36 | }
37 | })
38 | ])
39 | ])
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/btn/btn-group.ios.styl:
--------------------------------------------------------------------------------
1 | .q-btn-group
2 | border-radius $button-border-radius
3 | vertical-align middle
4 | > .q-btn-group
5 | > .q-btn:first-child
6 | border-top-left-radius inherit
7 | border-bottom-left-radius inherit
8 | > .q-btn:last-child
9 | border-top-right-radius inherit
10 | border-bottom-right-radius inherit
11 | > .q-btn-group:not(:first-child) > .q-btn:first-child
12 | border-left 0
13 | > .q-btn-group:not(:last-child) > .q-btn:last-child
14 | border-right 0
15 | > .q-btn-item:not(:last-child)
16 | border-top-right-radius 0
17 | border-bottom-right-radius 0
18 | > .q-btn-item + .q-btn-item
19 | border-top-left-radius 0
20 | border-bottom-left-radius 0
21 | .q-btn-group-push
22 | border-radius $button-push-border-radius
23 | > .q-btn-push
24 | .q-btn-inner
25 | transition $button-transition
26 | &:active:not(.disabled)
27 | &.active:not(.disabled)
28 | border-bottom-color rgba(0, 0, 0, .15)
29 | transform translateY(0)
30 | .q-btn-inner
31 | transform translateY(3px)
32 | .q-btn-group-rounded
33 | border-radius $button-rounded-border-radius
34 | .q-btn-group-outline
35 | > .q-btn-item + .q-btn-item
36 | border-left 0
37 | > .q-btn-item:not(:last-child)
38 | border-right 0
39 |
--------------------------------------------------------------------------------
/src/css/core/helpers.styl:
--------------------------------------------------------------------------------
1 | .backdrop
2 | display none
3 | position fixed
4 | top 0
5 | right 0
6 | bottom 0
7 | left 0
8 | width 100vw
9 | height 100vh
10 | background transparent
11 | transition background .28s ease-in
12 | &.active
13 | display block
14 | background $backdrop-background
15 |
16 | .round-borders
17 | border-radius $generic-border-radius !important
18 |
19 | .generic-margin, .group > * // @stylint ignore
20 | margin 5px
21 |
22 | .no-transition
23 | transition none !important
24 |
25 | .transition-0
26 | transition 0s !important
27 |
28 | .glossy
29 | background-image linear-gradient(to bottom, rgba(white, .3), rgba(white, 0) 50%, rgba(black, .12) 51%, rgba(black, .04)) !important
30 |
31 | .q-placeholder
32 | &::-webkit-input-placeholder
33 | color inherit
34 | opacity .5
35 | &::-moz-placeholder
36 | color inherit
37 | opacity .5
38 | &:-ms-input-placeholder
39 | color inherit
40 | opacity .5
41 |
42 | /* body */
43 | .q-body-fullscreen-mixin, .q-body-prevent-scroll
44 | overflow hidden !important
45 |
46 | .q-no-input-spinner
47 | -moz-appearance textfield
48 | &::-webkit-outer-spin-button,
49 | &::-webkit-inner-spin-button
50 | -webkit-appearance none
51 | margin 0
52 |
53 | a.q-link
54 | outline 0
55 | color inherit
56 | text-decoration none
57 |
--------------------------------------------------------------------------------
/src/utils/animate.js:
--------------------------------------------------------------------------------
1 | import uid from './uid.js'
2 | import { linear } from './easing.js'
3 |
4 | let ids = {}
5 |
6 | export function start ({name, duration = 300, to, from, apply, done, cancel, easing}) {
7 | let id = name
8 | const start = new Date()
9 |
10 | if (id) {
11 | stop(id)
12 | }
13 | else {
14 | id = uid()
15 | }
16 |
17 | const delta = easing || linear
18 | const handler = () => {
19 | let progress = ((new Date()) - start) / duration
20 | if (progress > 1) {
21 | progress = 1
22 | }
23 |
24 | const newPos = from + (to - from) * delta(progress)
25 | apply(newPos, progress)
26 |
27 | if (progress === 1) {
28 | delete ids[id]
29 | done && done(newPos)
30 | return
31 | }
32 |
33 | anim.last = {
34 | pos: newPos,
35 | progress
36 | }
37 | anim.timer = requestAnimationFrame(handler)
38 | }
39 |
40 | const anim = ids[id] = {
41 | cancel,
42 | timer: requestAnimationFrame(handler)
43 | }
44 |
45 | return id
46 | }
47 |
48 | export function stop (id) {
49 | if (!id) {
50 | return
51 | }
52 | let anim = ids[id]
53 | if (anim && anim.timer) {
54 | cancelAnimationFrame(anim.timer)
55 | anim.cancel && anim.cancel(anim.last)
56 | delete ids[id]
57 | }
58 | }
59 |
60 | export default {
61 | start,
62 | stop
63 | }
64 |
--------------------------------------------------------------------------------
/src/components/uploader/uploader.ios.styl:
--------------------------------------------------------------------------------
1 | .q-uploader-expanded .q-if
2 | border-bottom-left-radius 0
3 | border-bottom-right-radius 0
4 |
5 | .q-uploader-input
6 | opacity 0
7 | max-width 100%
8 | height 100%
9 | width 100%
10 | font-size 0
11 | .q-uploader-pick-button[disabled] .q-uploader-input
12 | display none
13 |
14 | .q-uploader-files
15 | border 1px solid $grey-4
16 | font-size 14px
17 | max-height 500px
18 | .q-uploader-files-no-border .q-uploader-files
19 | border-top 0 !important
20 | .q-uploader-file:not(:last-child)
21 | border-bottom 1px solid $grey-4
22 | .q-uploader-progress-bg, .q-uploader-progress-text
23 | pointer-events none
24 | .q-uploader-progress-bg
25 | height 100%
26 | opacity .2
27 | .q-uploader-progress-text
28 | font-size 40px
29 | opacity .1
30 | right 44px
31 | bottom 0
32 |
33 | .q-uploader-dnd
34 | outline 2px dashed currentColor
35 | outline-offset -6px
36 | background rgba(255, 255, 255, .6)
37 | &.inverted
38 | background rgba(0, 0, 0, .3)
39 |
40 | .q-uploader-dark
41 | .q-uploader-files
42 | color white
43 | border 1px solid $field-dark-label-color
44 | .q-uploader-bg
45 | color white
46 | .q-uploader-progress-text
47 | opacity .2
48 | .q-uploader-file:not(:last-child)
49 | border-bottom 1px solid $dark
50 | border-bottom 1px solid var(--q-color-dark)
51 |
--------------------------------------------------------------------------------
/src/components/uploader/uploader.mat.styl:
--------------------------------------------------------------------------------
1 | .q-uploader-expanded .q-if
2 | border-bottom-left-radius 0
3 | border-bottom-right-radius 0
4 |
5 | .q-uploader-input
6 | opacity 0
7 | max-width 100%
8 | height 100%
9 | width 100%
10 | font-size 0
11 | .q-uploader-pick-button[disabled] .q-uploader-input
12 | display none
13 |
14 | .q-uploader-files
15 | border 1px solid $grey-4
16 | font-size 14px
17 | max-height 500px
18 | .q-uploader-files-no-border .q-uploader-files
19 | border-top 0 !important
20 | .q-uploader-file:not(:last-child)
21 | border-bottom 1px solid $grey-4
22 | .q-uploader-progress-bg, .q-uploader-progress-text
23 | pointer-events none
24 | .q-uploader-progress-bg
25 | height 100%
26 | opacity .2
27 | .q-uploader-progress-text
28 | font-size 40px
29 | opacity .1
30 | right 44px
31 | bottom 0
32 |
33 | .q-uploader-dnd
34 | outline 2px dashed currentColor
35 | outline-offset -6px
36 | background rgba(255, 255, 255, .6)
37 | &.inverted
38 | background rgba(0, 0, 0, .3)
39 |
40 | .q-uploader-dark
41 | .q-uploader-files
42 | color white
43 | border 1px solid $field-dark-label-color
44 | .q-uploader-bg
45 | color white
46 | .q-uploader-progress-text
47 | opacity .2
48 | .q-uploader-file:not(:last-child)
49 | border-bottom 1px solid $dark
50 | border-bottom 1px solid var(--q-color-dark)
51 |
--------------------------------------------------------------------------------
/dev/components/other/app-visibility.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Switch to another
6 |
7 | tab in your browser
8 |
9 |
10 | App
11 |
12 | then come back here to see Visibility in action.
13 |
14 |
15 |
16 |
17 |
18 | {{ evt.timestamp }}
19 | {{ evt.label }}
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
52 |
--------------------------------------------------------------------------------
/src/components/toggle/toggle.ios.styl:
--------------------------------------------------------------------------------
1 | $toggle-width = 50px
2 | $toggle-height = 32px
3 | $toggle-span = 2px
4 | $toggle-handle-size = $toggle-height - 2 * $toggle-span
5 |
6 | .q-toggle-base
7 | transition all .45s cubic-bezier(.23, 1, .32, 1)
8 | width 100%
9 | height $toggle-height
10 | color $grey-2
11 | background currentColor
12 | border-radius 16px
13 | border 2px solid $light
14 | border 2px solid var(--q-color-light)
15 | .q-toggle-base-dark
16 | color darken($light, 10%)
17 | color var(--q-color-light-d)
18 |
19 | .q-toggle-handle
20 | background white
21 | box-shadow 0 3px 3px rgba(0, 0, 0, .2), 0 0 0 2px $light // @stylint ignore
22 | box-shadow 0 3px 3px rgba(0, 0, 0, .2), 0 0 0 2px var(--q-color-light) // @stylint ignore
23 | transition all 450ms cubic-bezier(.23, 1, .32, 1)
24 | border-radius 50%
25 | position absolute
26 | top $toggle-span
27 | left $toggle-span
28 | width $toggle-handle-size
29 | height $toggle-handle-size
30 | line-height $toggle-handle-size
31 |
32 | .q-toggle .q-option-inner
33 | height $toggle-height
34 | width $toggle-width
35 | min-width $toggle-width
36 | &.active
37 | .q-toggle-base
38 | color currentColor
39 | border 0
40 | .q-toggle-handle
41 | box-shadow $shadow-2
42 | left ($toggle-width - $toggle-handle-size - $toggle-span)
43 |
--------------------------------------------------------------------------------
/dev/components/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 | {{ title }}
14 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
51 |
--------------------------------------------------------------------------------
/dev/components/web-tests/breakpoints.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ type }}
4 |
5 |
{{ w }} - {{ width }}
6 |
7 |
8 |
9 |
58 |
--------------------------------------------------------------------------------
/src/components/spinner/QSpinnerOval.js:
--------------------------------------------------------------------------------
1 | import mixin from './spinner-mixin.js'
2 |
3 | export default {
4 | name: 'QSpinnerOval',
5 | mixins: [mixin],
6 | render (h) {
7 | return h('svg', {
8 | staticClass: 'q-spinner',
9 | class: this.classes,
10 | attrs: {
11 | 'stroke': 'currentColor',
12 | 'width': this.size,
13 | 'height': this.size,
14 | 'viewBox': '0 0 38 38',
15 | 'xmlns': 'http://www.w3.org/2000/svg'
16 | }
17 | }, [
18 | h('g', {
19 | attrs: {
20 | 'transform': 'translate(1 1)',
21 | 'stroke-width': '2',
22 | 'fill': 'none',
23 | 'fill-rule': 'evenodd'
24 | }
25 | }, [
26 | h('circle', {
27 | attrs: {
28 | 'stroke-opacity': '.5',
29 | 'cx': '18',
30 | 'cy': '18',
31 | 'r': '18'
32 | }
33 | }),
34 | h('path', {
35 | attrs: {
36 | 'd': 'M36 18c0-9.94-8.06-18-18-18'
37 | }
38 | }, [
39 | h('animateTransform', {
40 | attrs: {
41 | 'attributeName': 'transform',
42 | 'type': 'rotate',
43 | 'from': '0 18 18',
44 | 'to': '360 18 18',
45 | 'dur': '1s',
46 | 'repeatCount': 'indefinite'
47 | }
48 | })
49 | ])
50 | ])
51 | ])
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/utils/dom.js:
--------------------------------------------------------------------------------
1 | export function offset (el) {
2 | if (!el || el === window) {
3 | return {top: 0, left: 0}
4 | }
5 | let {top, left} = el.getBoundingClientRect()
6 |
7 | return {top, left}
8 | }
9 |
10 | export function style (el, property) {
11 | return window.getComputedStyle(el).getPropertyValue(property)
12 | }
13 |
14 | export function height (el) {
15 | if (el === window) {
16 | return window.innerHeight
17 | }
18 | return parseFloat(style(el, 'height'))
19 | }
20 |
21 | export function width (el) {
22 | if (el === window) {
23 | return window.innerWidth
24 | }
25 | return parseFloat(style(el, 'width'))
26 | }
27 |
28 | export function css (element, css) {
29 | let style = element.style
30 |
31 | Object.keys(css).forEach(prop => {
32 | style[prop] = css[prop]
33 | })
34 | }
35 |
36 | export function ready (fn) {
37 | if (typeof fn !== 'function') {
38 | return
39 | }
40 |
41 | if (document.readyState !== 'loading') {
42 | return fn()
43 | }
44 |
45 | document.addEventListener('DOMContentLoaded', fn, false)
46 | }
47 |
48 | const prefix = ['-webkit-', '-moz-', '-ms-', '-o-']
49 | export function cssTransform (val) {
50 | let o = {transform: val}
51 | prefix.forEach(p => {
52 | o[p + 'transform'] = val
53 | })
54 | return o
55 | }
56 |
57 | export default {
58 | offset,
59 | style,
60 | height,
61 | width,
62 | css,
63 | ready,
64 | cssTransform
65 | }
66 |
--------------------------------------------------------------------------------
/dev/components/components/scroll-area.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ n }} Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Click
8 |
9 |
10 |
11 |
Less
12 |
More
13 |
Scroll to 125
14 |
Scroll to 525 (animated)
15 |
16 |
17 |
18 |
19 |
20 |
37 |
--------------------------------------------------------------------------------
/src/components/btn/btn-group.mat.styl:
--------------------------------------------------------------------------------
1 | .q-btn-group
2 | border-radius $button-border-radius
3 | box-shadow $button-shadow
4 | vertical-align middle
5 | > .q-btn-item
6 | box-shadow none
7 | > .q-btn-group
8 | > .q-btn:first-child
9 | border-top-left-radius inherit
10 | border-bottom-left-radius inherit
11 | > .q-btn:last-child
12 | border-top-right-radius inherit
13 | border-bottom-right-radius inherit
14 | > .q-btn-group:not(:first-child) > .q-btn:first-child
15 | border-left 0
16 | > .q-btn-group:not(:last-child) > .q-btn:last-child
17 | border-right 0
18 | > .q-btn-item:not(:last-child)
19 | border-top-right-radius 0
20 | border-bottom-right-radius 0
21 | > .q-btn-item + .q-btn-item
22 | border-top-left-radius 0
23 | border-bottom-left-radius 0
24 | .q-btn-group-push
25 | border-radius $button-push-border-radius
26 | > .q-btn-push
27 | .q-btn-inner
28 | transition $button-transition
29 | &:active:not(.disabled)
30 | &.active:not(.disabled)
31 | border-bottom-color rgba(0, 0, 0, .15)
32 | transform translateY(0)
33 | .q-btn-inner
34 | transform translateY(3px)
35 | .q-btn-group-rounded
36 | border-radius $button-rounded-border-radius
37 | .q-btn-group-flat, .q-btn-group-outline
38 | box-shadow none
39 | .q-btn-group-outline
40 | > .q-btn-item + .q-btn-item
41 | border-left 0
42 | > .q-btn-item:not(:last-child)
43 | border-right 0
44 |
--------------------------------------------------------------------------------
/src/css/core/ripples.styl:
--------------------------------------------------------------------------------
1 | .q-ripple
2 |
3 | &-container
4 | top 0
5 | left 0
6 | width 100%
7 | height 100%
8 | position absolute
9 | color inherit
10 | border-radius inherit
11 | overflow hidden
12 | z-index 0
13 | pointer-events none
14 |
15 | &-animation
16 | top 0
17 | left 0 /* rtl:ignore */
18 | opacity 0
19 | color inherit
20 | position absolute
21 | border-radius 50%
22 | background currentColor
23 | transition .3s transform cubic-bezier(.2, .4, .4, .9), .3s opacity cubic-bezier(.2, .4, .4, .1)
24 | pointer-events none
25 | overflow hidden
26 | will-change transform, opacity
27 |
28 | &-enter
29 | transition none
30 |
31 | &-visible
32 | opacity .15
33 |
34 | .q-radial-ripple
35 | overflow hidden
36 | border-radius 50%
37 | pointer-events none
38 | position absolute
39 | top -50%
40 | left -50%
41 | width 200%
42 | height 200%
43 |
44 | &:after
45 | content ''
46 | display block
47 | position absolute
48 | top 0
49 | left 0
50 | right 0
51 | bottom 0
52 | background-image radial-gradient(circle, currentColor 10%, transparent 10.01%)
53 | background-repeat no-repeat
54 | background-position 50%
55 | transform scale(10, 10)
56 | opacity 0
57 | transition transform .5s, opacity 1s
58 |
59 | &.active:after
60 | transform scale(0, 0)
61 | opacity .4
62 | transition 0s
63 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Code of Conduct
2 |
3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4 |
5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6 |
7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8 |
9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10 |
11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12 |
13 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
14 |
--------------------------------------------------------------------------------
/dev/components/components/scroll-fire.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Please scroll down to see the image have a short bounce effect when being visible for first time.
5 |
{{ n }} {{ loremipsum }}
6 |
7 |
Scroll Fire below. Reload page to see the bounce effect again.
8 |
9 |
10 |
11 |
12 |
{{ n }} {{ loremipsum }}
13 |
14 |
15 |
16 |
17 |
36 |
--------------------------------------------------------------------------------
/src/components/fab/fab.ios.styl:
--------------------------------------------------------------------------------
1 | .q-fab
2 | position relative
3 | vertical-align middle
4 |
5 | .z-fab
6 | z-index $z-fab
7 |
8 | .q-fab-opened
9 | .q-fab-actions
10 | opacity 1
11 | transform scaleX(1) scaleY(1) translateX(0) translateY(0)
12 | pointer-events all
13 | .q-fab-icon
14 | transform rotate3d(0, 0, 1, 180deg)
15 | opacity 0
16 | .q-fab-active-icon
17 | transform rotate3d(0, 0, 1, 0deg)
18 | opacity 1
19 |
20 | .q-fab-icon, .q-fab-active-icon
21 | transition opacity .4s, transform .4s
22 | .q-fab-icon
23 | opacity 1
24 | transform rotate3d(0, 0, 1, 0deg)
25 | .q-fab-active-icon
26 | opacity 0
27 | transform rotate3d(0, 0, 1, -180deg)
28 |
29 | .q-fab-actions
30 | position absolute
31 | opacity 0
32 | transition all .2s ease-in
33 | pointer-events none
34 | .q-btn
35 | margin $fab-margin
36 |
37 | .q-fab-right
38 | transform scaleX(.4) scaleY(.4) translateX(-100%)
39 | top 0
40 | bottom 0
41 | left 120%
42 | .q-fab-left
43 | transform scaleX(.4) scaleY(.4) translateX(100%)
44 | top 0
45 | bottom 0
46 | right 120%
47 | flex-direction row-reverse
48 | .q-fab-up
49 | transform scaleX(.4) scaleY(.4) translateY(100%)
50 | flex-direction column-reverse
51 | justify-content center
52 | bottom 120%
53 | left 0
54 | right 0
55 | .q-fab-down
56 | transform scaleX(.4) scaleY(.4) translateY(-100%)
57 | flex-direction column
58 | justify-content center
59 | top 120%
60 | left 0
61 | right 0
62 |
--------------------------------------------------------------------------------
/src/components/fab/fab.mat.styl:
--------------------------------------------------------------------------------
1 | .q-fab
2 | position relative
3 | vertical-align middle
4 |
5 | .z-fab
6 | z-index $z-fab
7 |
8 | .q-fab-opened
9 | .q-fab-actions
10 | opacity 1
11 | transform scaleX(1) scaleY(1) translateX(0) translateY(0)
12 | pointer-events all
13 | .q-fab-icon
14 | transform rotate3d(0, 0, 1, 180deg)
15 | opacity 0
16 | .q-fab-active-icon
17 | transform rotate3d(0, 0, 1, 0deg)
18 | opacity 1
19 |
20 | .q-fab-icon, .q-fab-active-icon
21 | transition opacity .4s, transform .4s
22 | .q-fab-icon
23 | opacity 1
24 | transform rotate3d(0, 0, 1, 0deg)
25 | .q-fab-active-icon
26 | opacity 0
27 | transform rotate3d(0, 0, 1, -180deg)
28 |
29 | .q-fab-actions
30 | position absolute
31 | opacity 0
32 | transition all .2s ease-in
33 | pointer-events none
34 | .q-btn
35 | margin $fab-margin
36 |
37 | .q-fab-right
38 | transform scaleX(.4) scaleY(.4) translateX(-100%)
39 | top 0
40 | bottom 0
41 | left 120%
42 | .q-fab-left
43 | transform scaleX(.4) scaleY(.4) translateX(100%)
44 | top 0
45 | bottom 0
46 | right 120%
47 | flex-direction row-reverse
48 | .q-fab-up
49 | transform scaleX(.4) scaleY(.4) translateY(100%)
50 | flex-direction column-reverse
51 | justify-content center
52 | bottom 120%
53 | left 0
54 | right 0
55 | .q-fab-down
56 | transform scaleX(.4) scaleY(.4) translateY(-100%)
57 | flex-direction column
58 | justify-content center
59 | top 120%
60 | left 0
61 | right 0
62 |
--------------------------------------------------------------------------------
/dev/components/components/infinite-scroll.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Scroll down to see it in action.
5 |
6 |
7 |
8 |
9 |
10 | {{ index + 1 }}
11 |
12 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
46 |
--------------------------------------------------------------------------------
/dev/components/components/popover-test.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
50 |
--------------------------------------------------------------------------------
/src/components/radio/QRadio.js:
--------------------------------------------------------------------------------
1 | import OptionMixin from '../../mixins/option.js'
2 | import QIcon from '../icon/QIcon.js'
3 | import { stopAndPrevent } from '../../utils/event.js'
4 |
5 | export default {
6 | name: 'QRadio',
7 | mixins: [OptionMixin],
8 | props: {
9 | val: {
10 | required: true
11 | }
12 | },
13 | computed: {
14 | isTrue () {
15 | return this.value === this.val
16 | }
17 | },
18 | methods: {
19 | toggle (evt, blur = true) {
20 | if (this.disable || this.readonly) {
21 | return
22 | }
23 | evt && stopAndPrevent(evt)
24 | blur && this.$el.blur()
25 |
26 | if (!this.isTrue) {
27 | this.__update(this.val)
28 | }
29 | },
30 | __getContent (h) {
31 | return [
32 | h(QIcon, {
33 | staticClass: 'q-radio-unchecked cursor-pointer absolute-full',
34 | props: {
35 | name: this.uncheckedIcon || this.$q.icon.radio.unchecked[process.env.THEME]
36 | }
37 | }),
38 | h(QIcon, {
39 | staticClass: 'q-radio-checked cursor-pointer absolute-full',
40 | props: {
41 | name: this.checkedIcon || this.$q.icon.radio.checked[process.env.THEME]
42 | }
43 | }),
44 | process.env.THEME === 'mat'
45 | ? h('div', { ref: 'ripple', staticClass: 'q-radial-ripple' })
46 | : null
47 | ]
48 | }
49 | },
50 | beforeCreate () {
51 | this.__kebabTag = 'q-radio'
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/directives/scroll.js:
--------------------------------------------------------------------------------
1 | import { getScrollPosition, getScrollTarget, getHorizontalScrollPosition } from '../utils/scroll.js'
2 | import { listenOpts } from '../utils/event.js'
3 |
4 | function updateBinding (el, binding) {
5 | const ctx = el.__qscroll
6 |
7 | if (typeof binding.value !== 'function') {
8 | ctx.scrollTarget.removeEventListener('scroll', ctx.scroll, listenOpts.passive)
9 | console.error('v-scroll requires a function as parameter', el)
10 | return
11 | }
12 |
13 | ctx.handler = binding.value
14 | if (typeof binding.oldValue !== 'function') {
15 | ctx.scrollTarget.addEventListener('scroll', ctx.scroll, listenOpts.passive)
16 | }
17 | }
18 |
19 | export default {
20 | name: 'scroll',
21 | bind (el, binding) {
22 | let ctx = {
23 | scroll () {
24 | ctx.handler(
25 | getScrollPosition(ctx.scrollTarget),
26 | getHorizontalScrollPosition(ctx.scrollTarget)
27 | )
28 | }
29 | }
30 | el.__qscroll = ctx
31 | },
32 | inserted (el, binding) {
33 | let ctx = el.__qscroll
34 | ctx.scrollTarget = getScrollTarget(el)
35 | updateBinding(el, binding)
36 | },
37 | update (el, binding) {
38 | if (binding.oldValue !== binding.value) {
39 | updateBinding(el, binding)
40 | }
41 | },
42 | unbind (el) {
43 | let ctx = el.__qscroll
44 | if (!ctx) { return }
45 | ctx.scrollTarget.removeEventListener('scroll', ctx.scroll, listenOpts.passive)
46 | delete el.__qscroll
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/dev/components/other/vue-transitions.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
"Slide" Transition
5 |
6 |
7 | Click
8 | Tap
9 | on the Toggle below to see the transition in action.
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
54 |
--------------------------------------------------------------------------------
/src/components/datetime/datetime-props.js:
--------------------------------------------------------------------------------
1 | import { isDate } from '../../utils/is'
2 |
3 | export const modelValidator = v => {
4 | const type = typeof v
5 | return (
6 | v === null || v === undefined ||
7 | type === 'number' || type === 'string' ||
8 | isDate(v)
9 | )
10 | }
11 |
12 | export const inline = {
13 | value: {
14 | validator: modelValidator,
15 | required: true
16 | },
17 | defaultValue: {
18 | type: [String, Number, Date],
19 | default: null
20 | },
21 | type: {
22 | type: String,
23 | default: 'date',
24 | validator: v => ['date', 'time', 'datetime'].includes(v)
25 | },
26 | color: {
27 | type: String,
28 | default: 'primary'
29 | },
30 | dark: Boolean,
31 | min: {
32 | validator: modelValidator,
33 | default: null
34 | },
35 | max: {
36 | validator: modelValidator,
37 | default: null
38 | },
39 | headerLabel: String,
40 | firstDayOfWeek: Number,
41 | formatModel: {
42 | type: String,
43 | default: 'auto',
44 | validator: v => ['auto', 'date', 'number', 'string'].includes(v)
45 | },
46 | format24h: {
47 | type: [Boolean, Number],
48 | default: 0,
49 | validator: v => [true, false, 0].includes(v)
50 | },
51 | defaultView: {
52 | type: String,
53 | validator: v => ['year', 'month', 'day', 'hour', 'minute'].includes(v)
54 | },
55 | minimal: Boolean
56 | }
57 |
58 | export const input = {
59 | format: String,
60 | okLabel: String,
61 | cancelLabel: String,
62 | displayValue: String
63 | }
64 |
--------------------------------------------------------------------------------
/dev/app.js:
--------------------------------------------------------------------------------
1 | import '../src/ie-compat/ie'
2 | import Vue from 'vue'
3 | import App from './App.vue'
4 |
5 | import { createRouter } from './router'
6 |
7 | // this imports everything from Quasar
8 | import Quasar from 'quasar'
9 |
10 | import 'quasar-css'
11 | import './app.styl'
12 | // import iconSet from '../icons/fontawesome'
13 |
14 | import 'quasar-extras/fontawesome/fontawesome.css'
15 | import 'quasar-extras/mdi/mdi.css'
16 | import 'quasar-extras/ionicons/ionicons.css'
17 | import 'quasar-extras/animate/fadeIn.css'
18 | import 'quasar-extras/animate/fadeOut.css'
19 |
20 | Vue.use(Quasar, {
21 | // iconSet,
22 | config: {}
23 | })
24 |
25 | const testHydration = true
26 |
27 | // export a factory function for creating fresh app, router and store
28 | // instances
29 | export function createApp (ssrContext) {
30 | const router = createRouter()
31 |
32 | // we get each page from server first!
33 | if (testHydration && process.env.CLIENT) {
34 | console.log('[Quasar] !!!!')
35 | console.log('[Quasar] On route change we deliberately load page from server -- in order to test hydration errors')
36 | console.log('[Quasar] !!!!')
37 |
38 | let reload = false
39 | router.beforeEach((to, from, next) => {
40 | if (reload) {
41 | window.location.href = to.fullPath
42 | return
43 | }
44 | reload = true
45 | next()
46 | })
47 | }
48 |
49 | const app = {
50 | router,
51 | render: h => h(App)
52 | }
53 |
54 | Quasar.ssrUpdate({ app, ssr: ssrContext })
55 |
56 | return {
57 | app: new Vue(app),
58 | router
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/mixins/item.js:
--------------------------------------------------------------------------------
1 | import { routerLinkProps } from '../utils/router-link.js'
2 |
3 | export function textStyle (n) {
4 | return n === void 0 || n < 2
5 | ? {}
6 | : {overflow: 'hidden', display: '-webkit-box', '-webkit-box-orient': 'vertical', '-webkit-line-clamp': n}
7 | }
8 |
9 | export const subItemProps = {
10 | icon: String,
11 | rightIcon: String,
12 | image: String,
13 | rightImage: String,
14 | avatar: String,
15 | rightAvatar: String,
16 | letter: String,
17 | rightLetter: String,
18 | label: String,
19 | sublabel: String,
20 | labelLines: [String, Number],
21 | sublabelLines: [String, Number]
22 | }
23 |
24 | export default {
25 | mixins: [{ props: routerLinkProps }],
26 | props: {
27 | dark: Boolean,
28 |
29 | link: Boolean,
30 | dense: Boolean,
31 | sparse: Boolean,
32 | separator: Boolean,
33 | insetSeparator: Boolean,
34 | multiline: Boolean,
35 | highlight: Boolean,
36 |
37 | tag: {
38 | type: String,
39 | default: 'div'
40 | }
41 | },
42 | computed: {
43 | itemClasses () {
44 | return {
45 | 'q-item': true,
46 | 'q-item-division': true,
47 | 'relative-position': true,
48 | 'q-item-dark': this.dark,
49 | 'q-item-dense': this.dense,
50 | 'q-item-sparse': this.sparse,
51 | 'q-item-separator': this.separator,
52 | 'q-item-inset-separator': this.insetSeparator,
53 | 'q-item-multiline': this.multiline,
54 | 'q-item-highlight': this.highlight,
55 | 'q-item-link': this.to || this.link
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/dev/components/css/material-ripples.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Click
6 | Tap
7 | on the area below to see it in action.
8 |
9 |
10 |
15 |
16 |
17 |
18 |
23 |
24 |
25 |
26 |
27 |
53 |
54 |
66 |
--------------------------------------------------------------------------------
/src/components/card/card.ios.styl:
--------------------------------------------------------------------------------
1 | .q-card
2 | border-radius $generic-border-radius
3 | box-shadow $card-shadow
4 | vertical-align top
5 |
6 | > div:first-child
7 | border-top-left-radius inherit
8 | border-top-right-radius inherit
9 | > div:last-child
10 | border-bottom-left-radius inherit
11 | border-bottom-right-radius inherit
12 |
13 | > .q-list
14 | border 0
15 |
16 | .q-card-separator
17 | background $card-separator-color
18 | height 1px
19 | &.inset
20 | margin 0 16px
21 |
22 | .q-card-container
23 | padding 16px
24 |
25 | .q-card-title
26 | font-size 18px
27 | font-weight 400
28 | letter-spacing normal
29 | line-height 2rem
30 | &:empty
31 | display none
32 | .q-card-subtitle, .q-card-title-extra
33 | font-size 14px
34 | color $card-faded-color
35 | .q-icon
36 | font-size 24px
37 |
38 | .q-card-main
39 | font-size 14px
40 | .q-card-primary + .q-card-main
41 | padding-top 0
42 |
43 | .q-card-actions
44 | padding 8px
45 | .q-btn
46 | padding 0 8px
47 | .q-card-actions-horiz
48 | .q-btn + .q-btn
49 | margin-left 8px
50 | .q-card-actions-vert
51 | .q-btn + .q-btn
52 | margin-top 4px
53 |
54 | .q-card-media
55 | overflow hidden
56 | > img
57 | display block
58 | width 100%
59 | max-width 100%
60 | border 0
61 | .q-card-media-overlay
62 | color white
63 | background $card-overlay-color
64 | .q-card-subtitle
65 | color white
66 |
67 | .q-card-dark
68 | .q-card-separator
69 | background $card-dark-separator-color
70 | .q-card-subtitle, .q-card-title-extra
71 | color $card-dark-faded-color
72 |
--------------------------------------------------------------------------------
/src/components/card/card.mat.styl:
--------------------------------------------------------------------------------
1 | .q-card
2 | border-radius $generic-border-radius
3 | box-shadow $card-shadow
4 | vertical-align top
5 |
6 | > div:first-child
7 | border-top-left-radius inherit
8 | border-top-right-radius inherit
9 | > div:last-child
10 | border-bottom-left-radius inherit
11 | border-bottom-right-radius inherit
12 |
13 | > .q-list
14 | border 0
15 |
16 | .q-card-separator
17 | background $card-separator-color
18 | height 1px
19 | &.inset
20 | margin 0 16px
21 |
22 | .q-card-container
23 | padding 16px
24 |
25 | .q-card-title
26 | font-size 18px
27 | font-weight 400
28 | letter-spacing normal
29 | line-height 2rem
30 | &:empty
31 | display none
32 | .q-card-subtitle, .q-card-title-extra
33 | font-size 14px
34 | color $card-faded-color
35 | .q-icon
36 | font-size 24px
37 |
38 | .q-card-main
39 | font-size 14px
40 | .q-card-primary + .q-card-main
41 | padding-top 0
42 |
43 | .q-card-actions
44 | padding 8px
45 | .q-btn
46 | padding 0 8px
47 | .q-card-actions-horiz
48 | .q-btn + .q-btn
49 | margin-left 8px
50 | .q-card-actions-vert
51 | .q-btn + .q-btn
52 | margin-top 4px
53 |
54 | .q-card-media
55 | overflow hidden
56 | > img
57 | display block
58 | width 100%
59 | max-width 100%
60 | border 0
61 | .q-card-media-overlay
62 | color white
63 | background $card-overlay-color
64 | .q-card-subtitle
65 | color white
66 |
67 | .q-card-dark
68 | .q-card-separator
69 | background $card-dark-separator-color
70 | .q-card-subtitle, .q-card-title-extra
71 | color $card-dark-faded-color
72 |
--------------------------------------------------------------------------------
/src/components/icon/QIcon.js:
--------------------------------------------------------------------------------
1 | const prefix = process.env.THEME === 'mat' ? 'md' : 'ios'
2 |
3 | export default {
4 | name: 'QIcon',
5 | props: {
6 | name: String,
7 | color: String,
8 | size: String
9 | },
10 | computed: {
11 | classes () {
12 | let cls
13 | const icon = this.name
14 |
15 | if (!icon) {
16 | return ''
17 | }
18 | else if (/^fa[s|r|l|b]{0,1} /.test(icon) || icon.startsWith('icon-')) {
19 | cls = icon
20 | }
21 | else if (icon.startsWith('bt-')) {
22 | cls = `bt ${icon}`
23 | }
24 | else if (/^ion-(md|ios|logo)/.test(icon)) {
25 | cls = `ionicons ${icon}`
26 | }
27 | else if (icon.startsWith('ion-')) {
28 | cls = `ionicons ion-${prefix}${icon.substr(3)}`
29 | }
30 | else if (icon.startsWith('mdi-')) {
31 | cls = `mdi ${icon}`
32 | }
33 | else {
34 | cls = 'material-icons'
35 | }
36 |
37 | return this.color
38 | ? `${cls} text-${this.color}`
39 | : cls
40 | },
41 | content () {
42 | return this.classes.startsWith('material-icons')
43 | ? this.name.replace(/ /g, '_')
44 | : ' '
45 | },
46 | style () {
47 | if (this.size) {
48 | return { fontSize: this.size }
49 | }
50 | }
51 | },
52 | render (h) {
53 | return h('i', {
54 | staticClass: 'q-icon',
55 | 'class': this.classes,
56 | style: this.style,
57 | attrs: { 'aria-hidden': true }
58 | }, [
59 | this.content,
60 | this.$slots.default
61 | ])
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/components/spinner/index.js:
--------------------------------------------------------------------------------
1 | import QSpinner from './QSpinner.js'
2 |
3 | import QSpinnerAudio from './QSpinnerAudio.js'
4 | import QSpinnerBall from './QSpinnerBall.js'
5 | import QSpinnerBars from './QSpinnerBars.js'
6 | import QSpinnerCircles from './QSpinnerCircles.js'
7 | import QSpinnerComment from './QSpinnerComment.js'
8 | import QSpinnerCube from './QSpinnerCube.js'
9 | import QSpinnerDots from './QSpinnerDots.js'
10 | import QSpinnerFacebook from './QSpinnerFacebook.js'
11 | import QSpinnerGears from './QSpinnerGears.js'
12 | import QSpinnerGrid from './QSpinnerGrid.js'
13 | import QSpinnerHearts from './QSpinnerHearts.js'
14 | import QSpinnerHourglass from './QSpinnerHourglass.js'
15 | import QSpinnerInfinity from './QSpinnerInfinity.js'
16 | import QSpinnerIos from './QSpinner.ios.js'
17 | import QSpinnerMat from './QSpinner.mat.js'
18 | import QSpinnerOval from './QSpinnerOval.js'
19 | import QSpinnerPie from './QSpinnerPie.js'
20 | import QSpinnerPuff from './QSpinnerPuff.js'
21 | import QSpinnerRadio from './QSpinnerRadio.js'
22 | import QSpinnerRings from './QSpinnerRings.js'
23 | import QSpinnerTail from './QSpinnerTail.js'
24 |
25 | export {
26 | QSpinner,
27 |
28 | QSpinnerAudio,
29 | QSpinnerBall,
30 | QSpinnerBars,
31 | QSpinnerCircles,
32 | QSpinnerComment,
33 | QSpinnerCube,
34 | QSpinnerDots,
35 | QSpinnerFacebook,
36 | QSpinnerGears,
37 | QSpinnerGrid,
38 | QSpinnerHearts,
39 | QSpinnerHourglass,
40 | QSpinnerInfinity,
41 | QSpinnerIos,
42 | QSpinnerMat,
43 | QSpinnerOval,
44 | QSpinnerPie,
45 | QSpinnerPuff,
46 | QSpinnerRadio,
47 | QSpinnerRings,
48 | QSpinnerTail
49 | }
50 |
--------------------------------------------------------------------------------
/dev/components/components/no-ssr.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
1. Basic
4 |
5 | This won't be rendered on server
6 |
7 |
8 |
2. Multiple client nodes
9 |
10 | This won't be rendered on server.
11 | This won't either.
12 |
13 |
14 |
3. Multiple client nodes with tag prop
15 |
16 | This won't be rendered on server.
17 | This won't either.
18 |
19 |
20 |
4. Placeholder prop
21 |
22 | This won't be rendered on server
23 |
24 |
25 |
5. Placeholder slot
26 |
27 | This won't be rendered on server
28 | Rendered on server
29 |
30 |
31 |
6. Multiple placeholder slot
32 |
33 | This won't be rendered on server
34 | Rendered on server (1/2)
35 | Rendered on server (2/2)
36 |
37 |
38 |
7. Only placeholder slot
39 |
40 | Rendered on server
41 |
42 |
43 |
44 |
45 |
50 |
--------------------------------------------------------------------------------
/dev/components/form/rating.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Model {{ ratingModel }}
6 |
7 |
8 |
9 |
10 |
11 | { ratingModel = val; onChange(val); }" @input="onInput"/>
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Readonly State
19 |
20 |
21 |
Disabled State
22 |
23 |
24 |
25 |
26 |
27 |
49 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | **What kind of change does this PR introduce?** (check at least one)
10 |
11 | - [ ] Bugfix
12 | - [ ] Feature
13 | - [ ] Code style update
14 | - [ ] Refactor
15 | - [ ] Build-related changes
16 | - [ ] Other, please describe:
17 |
18 | **Does this PR introduce a breaking change?** (check one)
19 |
20 | - [ ] Yes
21 | - [ ] No
22 |
23 | If yes, please describe the impact and migration path for existing applications:
24 |
25 | **The PR fulfills these requirements:**
26 |
27 | - [ ] It's submitted to the `dev` branch and _not_ the `master` branch
28 | - [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix: #xxx[,#xxx]`, where "xxx" is the issue number)
29 | - [ ] It's been tested with all Quasar themes
30 | - [ ] It's been tested on a Cordova (iOS, Android) app
31 | - [ ] It's been tested on a Electron app
32 | - [ ] Any necessary documentation has been added or updated [in the docs](https://github.com/quasarframework/quasar-framework.org/tree/dev/source) (for faster update click on "Suggest an edit on GitHub" at bottom of page) or explained in the PR's description.
33 |
34 | If adding a **new feature**, the PR's description includes:
35 | - [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)
36 |
37 | **Other information:**
38 |
--------------------------------------------------------------------------------
/src/i18n.js:
--------------------------------------------------------------------------------
1 | import langEn from '../i18n/en-us.js'
2 | import { isSSR } from './plugins/platform.js'
3 |
4 | export default {
5 | install ($q, queues, Vue, lang) {
6 | if (isSSR) {
7 | queues.server.push((q, ctx) => {
8 | const
9 | opt = {
10 | lang: q.i18n.lang,
11 | dir: q.i18n.rtl ? 'rtl' : 'ltr'
12 | },
13 | fn = ctx.ssr.setHtmlAttrs
14 |
15 | if (typeof fn === 'function') {
16 | fn(opt)
17 | }
18 | else {
19 | ctx.ssr.Q_HTML_ATTRS = Object.keys(opt)
20 | .map(key => `${key}=${opt[key]}`)
21 | .join(' ')
22 | }
23 | })
24 | }
25 |
26 | this.set = (lang = langEn) => {
27 | lang.set = this.set
28 | lang.getLocale = this.getLocale
29 | lang.rtl = lang.rtl || false
30 |
31 | if (!isSSR) {
32 | const el = document.documentElement
33 | el.setAttribute('dir', lang.rtl ? 'rtl' : 'ltr')
34 | el.setAttribute('lang', lang.lang)
35 | }
36 |
37 | if (isSSR || $q.i18n) {
38 | $q.i18n = lang
39 | }
40 | else {
41 | Vue.util.defineReactive($q, 'i18n', lang)
42 | }
43 |
44 | this.name = lang.lang
45 | this.lang = lang
46 | }
47 |
48 | this.set(lang)
49 | },
50 |
51 | getLocale () {
52 | if (isSSR) { return }
53 |
54 | let val =
55 | navigator.language ||
56 | navigator.languages[0] ||
57 | navigator.browserLanguage ||
58 | navigator.userLanguage ||
59 | navigator.systemLanguage
60 |
61 | if (val) {
62 | return val.toLowerCase()
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/mixins/checkbox.js:
--------------------------------------------------------------------------------
1 | import { stopAndPrevent } from '../utils/event.js'
2 | import TouchSwipe from '../directives/touch-swipe.js'
3 |
4 | export default {
5 | directives: {
6 | TouchSwipe
7 | },
8 | props: {
9 | val: {},
10 | trueValue: { default: true },
11 | falseValue: { default: false }
12 | },
13 | computed: {
14 | isTrue () {
15 | return this.modelIsArray
16 | ? this.index > -1
17 | : this.value === this.trueValue
18 | },
19 | isFalse () {
20 | return this.modelIsArray
21 | ? this.index === -1
22 | : this.value === this.falseValue
23 | },
24 | index () {
25 | if (this.modelIsArray) {
26 | return this.value.indexOf(this.val)
27 | }
28 | },
29 | modelIsArray () {
30 | return Array.isArray(this.value)
31 | }
32 | },
33 | methods: {
34 | toggle (evt, blur = true) {
35 | if (this.disable || this.readonly) {
36 | return
37 | }
38 | evt && stopAndPrevent(evt)
39 | blur && this.$el.blur()
40 |
41 | let val
42 |
43 | if (this.modelIsArray) {
44 | if (this.isTrue) {
45 | val = this.value.slice()
46 | val.splice(this.index, 1)
47 | }
48 | else {
49 | val = this.value.concat(this.val)
50 | }
51 | }
52 | else if (this.isTrue) {
53 | val = this.toggleIndeterminate ? this.indeterminateValue : this.falseValue
54 | }
55 | else if (this.isFalse) {
56 | val = this.trueValue
57 | }
58 | else {
59 | val = this.falseValue
60 | }
61 |
62 | this.__update(val)
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | parser: 'babel-eslint',
5 | sourceType: 'module'
6 | },
7 | env: {
8 | browser: true
9 | },
10 | extends: [
11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
12 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
13 | 'plugin:vue/strongly-recommended',
14 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
15 | 'standard'
16 | ],
17 | // required to lint *.vue files
18 | plugins: [
19 | 'vue'
20 | ],
21 | globals: {
22 | 'cordova': true,
23 | '__THEME__': true,
24 | '__statics': true
25 | },
26 | // add your custom rules here
27 | 'rules': {
28 | 'brace-style': [2, 'stroustrup', { 'allowSingleLine': true }],
29 |
30 | 'vue/max-attributes-per-line': 0,
31 | 'vue/valid-v-for': 0,
32 | 'vue/require-default-prop': 0,
33 | 'vue/require-prop-types': 0,
34 | 'vue/require-v-for-key': 0,
35 |
36 | // allow async-await
37 | 'generator-star-spacing': 'off',
38 |
39 | // allow paren-less arrow functions
40 | 'arrow-parens': 0,
41 | 'one-var': 0,
42 |
43 | 'import/first': 0,
44 | 'import/named': 2,
45 | 'import/namespace': 2,
46 | 'import/default': 2,
47 | 'import/export': 2,
48 | 'import/extensions': 0,
49 | 'import/no-unresolved': 0,
50 | 'import/no-extraneous-dependencies': 0,
51 |
52 | 'prefer-promise-reject-errors': 0,
53 |
54 | // allow debugger during development
55 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/utils/prevent-scroll.js:
--------------------------------------------------------------------------------
1 | import { getEventPath, stopAndPrevent } from './event.js'
2 | import { hasScrollbar } from './scroll.js'
3 | import Platform from '../plugins/platform.js'
4 |
5 | let registered = 0
6 |
7 | function onWheel (e) {
8 | if (shouldPreventScroll(e)) {
9 | stopAndPrevent(e)
10 | }
11 | }
12 |
13 | function shouldPreventScroll (e) {
14 | if (e.target === document.body || e.target.classList.contains('q-layout-backdrop')) {
15 | return true
16 | }
17 |
18 | const
19 | path = getEventPath(e),
20 | shift = e.shiftKey && !e.deltaX,
21 | scrollY = !shift && Math.abs(e.deltaX) <= Math.abs(e.deltaY),
22 | delta = shift || scrollY ? e.deltaY : e.deltaX
23 |
24 | for (let index = 0; index < path.length; index++) {
25 | const el = path[index]
26 |
27 | if (hasScrollbar(el, scrollY)) {
28 | return scrollY
29 | ? (
30 | delta < 0 && el.scrollTop === 0
31 | ? true
32 | : delta > 0 && el.scrollTop + el.clientHeight === el.scrollHeight
33 | )
34 | : (
35 | delta < 0 && el.scrollLeft === 0
36 | ? true
37 | : delta > 0 && el.scrollLeft + el.clientWidth === el.scrollWidth
38 | )
39 | }
40 | }
41 |
42 | return true
43 | }
44 |
45 | export default function (register) {
46 | registered += register ? 1 : -1
47 | if (registered > 1) { return }
48 |
49 | const action = register ? 'add' : 'remove'
50 |
51 | if (Platform.is.mobile) {
52 | document.body.classList[action]('q-body-prevent-scroll')
53 | }
54 | else if (Platform.is.desktop) {
55 | window[`${action}EventListener`]('wheel', onWheel)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/mixins/fullscreen.js:
--------------------------------------------------------------------------------
1 | import History from '../history.js'
2 |
3 | export default {
4 | data () {
5 | return {
6 | inFullscreen: false
7 | }
8 | },
9 | watch: {
10 | $route () {
11 | this.exitFullscreen()
12 | },
13 | inFullscreen (v) {
14 | this.$emit('fullscreen', v)
15 | }
16 | },
17 | methods: {
18 | toggleFullscreen () {
19 | if (this.inFullscreen) {
20 | this.exitFullscreen()
21 | }
22 | else {
23 | this.setFullscreen()
24 | }
25 | },
26 | setFullscreen () {
27 | if (this.inFullscreen) {
28 | return
29 | }
30 |
31 | this.inFullscreen = true
32 | this.container = this.$el.parentNode
33 | this.container.replaceChild(this.fullscreenFillerNode, this.$el)
34 | document.body.appendChild(this.$el)
35 | document.body.classList.add('q-body-fullscreen-mixin')
36 |
37 | this.__historyFullscreen = {
38 | handler: this.exitFullscreen
39 | }
40 | History.add(this.__historyFullscreen)
41 | },
42 | exitFullscreen () {
43 | if (!this.inFullscreen) {
44 | return
45 | }
46 |
47 | if (this.__historyFullscreen) {
48 | History.remove(this.__historyFullscreen)
49 | this.__historyFullscreen = null
50 | }
51 | this.container.replaceChild(this.$el, this.fullscreenFillerNode)
52 | document.body.classList.remove('q-body-fullscreen-mixin')
53 | this.inFullscreen = false
54 | }
55 | },
56 | beforeMount () {
57 | this.fullscreenFillerNode = document.createElement('span')
58 | },
59 | beforeDestroy () {
60 | this.exitFullscreen()
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/dev/components/other/app-fullscreen.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Click
6 | Tap
7 | to switch between fullscreen mode and default mode.
8 |
9 |
10 |
Is fullscreen: {{ $q.fullscreen.isActive }}
11 |
12 |
13 |
19 |
20 |
21 |
27 |
28 |
29 |
30 | On some phones this will have little effect:
31 |
32 |
33 |
34 | For example, on Samsung S4, when App goes into fullscreen, the top bar
35 | will slide up but still remain on screen.
36 |
37 |
38 | On Nexus phones, on the other hand, like Nexus 5, Android navigation
39 | buttons and top bar dissapear completely.
40 |
41 |
42 |
43 |
44 |
45 |
46 |
60 |
--------------------------------------------------------------------------------
/src/css/core/size.styl:
--------------------------------------------------------------------------------
1 | :root
2 | for $name, $size in $sizes
3 | --q-size-{$name} $size
4 |
5 | .fit
6 | width 100% !important
7 | height 100% !important
8 | .full-height
9 | height 100% !important
10 | .full-width
11 | width 100% !important
12 | margin-left 0 !important
13 | margin-right 0 !important
14 |
15 | .window-height
16 | margin-top 0 !important
17 | margin-bottom 0 !important
18 | height 100vh !important
19 | .window-width
20 | margin-left 0 !important
21 | margin-right 0 !important
22 | width 100vw !important
23 |
24 | .block
25 | display block !important
26 | .inline-block
27 | display inline-block !important
28 |
29 | for $space, $value in $spaces
30 |
31 | .q-pa-{$space}
32 | padding: $value.y $value.x
33 | .q-pl-{$space}
34 | padding-left: $value.x
35 | .q-pr-{$space}
36 | padding-right: $value.x
37 | .q-pt-{$space}
38 | padding-top: $value.y
39 | .q-pb-{$space}
40 | padding-bottom: $value.y
41 | .q-px-{$space}
42 | @extends .q-pl-{$space}, .q-pr-{$space}
43 | .q-py-{$space}
44 | @extends .q-pt-{$space}, .q-pb-{$space}
45 |
46 | .q-ma-{$space}
47 | margin: $value.y $value.x
48 | .q-ml-{$space}
49 | margin-left: $value.x
50 | .q-mr-{$space}
51 | margin-right: $value.x
52 | .q-mt-{$space}
53 | margin-top: $value.y
54 | .q-mb-{$space}
55 | margin-bottom: $value.y
56 | .q-mx-{$space}
57 | @extends .q-ml-{$space}, .q-mr-{$space}
58 | .q-my-{$space}
59 | @extends .q-mt-{$space}, .q-mb-{$space}
60 |
61 | .q-ml-auto
62 | margin-left auto
63 | .q-mr-auto
64 | margin-right auto
65 | .q-mx-auto
66 | @extends .q-ml-auto, .q-mr-auto
67 |
68 | .q-my-form
69 | margin-top $input-margin-top
70 | margin-bottom $input-margin-bottom
71 |
--------------------------------------------------------------------------------
/src/components/toggle/QToggle.js:
--------------------------------------------------------------------------------
1 | import CheckboxMixin from '../../mixins/checkbox.js'
2 | import OptionMixin from '../../mixins/option.js'
3 | import QIcon from '../icon/QIcon.js'
4 |
5 | export default {
6 | name: 'QToggle',
7 | mixins: [CheckboxMixin, OptionMixin],
8 | props: {
9 | icon: String
10 | },
11 | computed: {
12 | currentIcon () {
13 | return (this.isTrue ? this.checkedIcon : this.uncheckedIcon) || this.icon
14 | },
15 | iconColor () {
16 | return process.env.THEME === 'ios'
17 | ? 'dark'
18 | : (this.isTrue ? 'white' : 'dark')
19 | },
20 | baseClass () {
21 | if (process.env.THEME === 'ios' && this.dark) {
22 | return `q-toggle-base-dark`
23 | }
24 | }
25 | },
26 | methods: {
27 | __swipe (evt) {
28 | if (evt.direction === 'left') {
29 | if (this.isTrue) {
30 | this.toggle()
31 | }
32 | }
33 | else if (evt.direction === 'right') {
34 | if (this.isFalse) {
35 | this.toggle()
36 | }
37 | }
38 | },
39 | __getContent (h) {
40 | return [
41 | h('div', { staticClass: 'q-toggle-base', 'class': this.baseClass }),
42 | h('div', { staticClass: 'q-toggle-handle row flex-center' }, [
43 | this.currentIcon
44 | ? h(QIcon, {
45 | staticClass: 'q-toggle-icon',
46 | props: { name: this.currentIcon, color: this.iconColor }
47 | })
48 | : null,
49 | process.env.THEME === 'mat'
50 | ? h('div', { ref: 'ripple', staticClass: 'q-radial-ripple' })
51 | : null
52 | ])
53 | ]
54 | }
55 | },
56 | beforeCreate () {
57 | this.__kebabTag = 'q-toggle'
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/dev/components/other/cookies.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Cookie Name
15 | Value
16 |
17 |
18 |
19 |
20 |
21 | {{ name }}
22 | {{ value }}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
57 |
--------------------------------------------------------------------------------
/src/plugins/app-fullscreen.js:
--------------------------------------------------------------------------------
1 | import { isSSR } from './platform.js'
2 |
3 | const prefixes = {}
4 |
5 | export default {
6 | isCapable: false,
7 | isActive: false,
8 |
9 | request (target) {
10 | if (this.isCapable && !this.isActive) {
11 | target = target || document.documentElement
12 | target[prefixes.request]()
13 | }
14 | },
15 | exit () {
16 | if (this.isCapable && this.isActive) {
17 | document[prefixes.exit]()
18 | }
19 | },
20 | toggle (target) {
21 | if (this.isActive) {
22 | this.exit()
23 | }
24 | else {
25 | this.request(target)
26 | }
27 | },
28 |
29 | install ({ $q, Vue }) {
30 | $q.fullscreen = this
31 |
32 | if (isSSR) { return }
33 |
34 | prefixes.request = [
35 | 'requestFullscreen',
36 | 'msRequestFullscreen', 'mozRequestFullScreen', 'webkitRequestFullscreen'
37 | ].find(request => document.documentElement[request])
38 |
39 | this.isCapable = prefixes.request !== undefined
40 | if (!this.isCapable) {
41 | // it means the browser does NOT support it
42 | return
43 | }
44 |
45 | prefixes.exit = [
46 | 'exitFullscreen',
47 | 'msExitFullscreen', 'mozCancelFullScreen', 'webkitExitFullscreen'
48 | ].find(exit => document[exit])
49 |
50 | this.isActive = !!(document.fullscreenElement ||
51 | document.mozFullScreenElement ||
52 | document.webkitFullscreenElement ||
53 | document.msFullscreenElement)
54 |
55 | ;[
56 | 'onfullscreenchange',
57 | 'onmsfullscreenchange', 'onmozfullscreenchange', 'onwebkitfullscreenchange'
58 | ].forEach(evt => {
59 | document[evt] = () => {
60 | this.isActive = !this.isActive
61 | }
62 | })
63 |
64 | Vue.util.defineReactive(this, 'isActive', this.isActive)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/plugins/addressbar-color.js:
--------------------------------------------------------------------------------
1 | import Platform, { isSSR } from './platform.js'
2 | import { getBrand } from '../utils/colors.js'
3 |
4 | let metaValue
5 |
6 | function getProp () {
7 | if (Platform.is.winphone) {
8 | return 'msapplication-navbutton-color'
9 | }
10 | if (Platform.is.safari) {
11 | return 'apple-mobile-web-app-status-bar-style'
12 | }
13 | // Chrome, Firefox OS, Opera, Vivaldi
14 | return 'theme-color'
15 | }
16 |
17 | function getMetaTag (v) {
18 | const els = document.getElementsByTagName('META')
19 | for (let i in els) {
20 | if (els[i].name === v) {
21 | return els[i]
22 | }
23 | }
24 | }
25 |
26 | function setColor (hexColor) {
27 | if (metaValue === void 0) {
28 | // cache it
29 | metaValue = getProp()
30 | }
31 |
32 | let metaTag = getMetaTag(metaValue)
33 | const newTag = metaTag === void 0
34 |
35 | if (newTag) {
36 | metaTag = document.createElement('meta')
37 | metaTag.setAttribute('name', metaValue)
38 | }
39 |
40 | metaTag.setAttribute('content', hexColor)
41 |
42 | if (newTag) {
43 | document.head.appendChild(metaTag)
44 | }
45 | }
46 |
47 | export default {
48 | install ({ $q, Vue, cfg }) {
49 | this.set = !isSSR && Platform.is.mobile && (
50 | Platform.is.cordova ||
51 | Platform.is.winphone || Platform.is.safari ||
52 | Platform.is.webkit || Platform.is.vivaldi
53 | )
54 | ? hexColor => {
55 | const val = hexColor || getBrand('primary')
56 |
57 | if (Platform.is.cordova && window.StatusBar) {
58 | window.StatusBar.backgroundColorByHexString(val)
59 | }
60 | else {
61 | setColor(val)
62 | }
63 | }
64 | : () => {}
65 |
66 | $q.addressbarColor = this
67 |
68 | cfg.addressbarColor && this.set(cfg.addressbarColor)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/dev/components/touch-directives/touch-hold.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Click and hold with your mouse
6 | Touch and hold
7 | on the area below to see it in action.
8 |
9 | Notice that on touch capable devices the scrolling is not blocked.
10 |
11 |
12 |
16 |
19 |
20 | Click/touch and hold for at least 800ms.
21 |
22 |
23 |
24 |
Configuring to trigger after custom time (in this case 3s):
25 |
29 |
30 |
{{ infoExtended }}
31 |
32 |
Click/touch and hold for 3 seconds
33 |
34 |
35 |
36 |
37 |
38 |
61 |
--------------------------------------------------------------------------------
/dev/components/other/close-overlay.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
20 |
21 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
58 |
--------------------------------------------------------------------------------
/src/css/core/positioning.styl:
--------------------------------------------------------------------------------
1 | .float-left
2 | float left
3 | .float-right
4 | float right
5 |
6 | .relative-position
7 | position relative
8 |
9 | .fixed,
10 | .fullscreen,
11 | .fixed-center,
12 | .fixed-bottom,
13 | .fixed-left,
14 | .fixed-right,
15 | .fixed-top,
16 | .fixed-top-left,
17 | .fixed-top-right,
18 | .fixed-bottom-left,
19 | .fixed-bottom-right
20 | position fixed
21 |
22 | .absolute,
23 | .absolute-full,
24 | .absolute-center,
25 | .absolute-bottom,
26 | .absolute-left,
27 | .absolute-right,
28 | .absolute-top,
29 | .absolute-top-left,
30 | .absolute-top-right,
31 | .absolute-bottom-left,
32 | .absolute-bottom-right
33 | position absolute
34 |
35 | .fixed-top, .absolute-top
36 | top 0
37 | left 0
38 | right 0
39 | .fixed-right, .absolute-right
40 | top 0
41 | right 0
42 | bottom 0
43 | .fixed-bottom, .absolute-bottom
44 | right 0
45 | bottom 0
46 | left 0
47 | .fixed-left, .absolute-left
48 | top 0
49 | bottom 0
50 | left 0
51 |
52 | .fixed-top-left, .absolute-top-left
53 | top 0
54 | left 0
55 | .fixed-top-right, .absolute-top-right
56 | top 0
57 | right 0
58 | .fixed-bottom-left, .absolute-bottom-left
59 | bottom 0
60 | left 0
61 | .fixed-bottom-right, .absolute-bottom-right
62 | bottom 0
63 | right 0
64 |
65 | .fullscreen
66 | z-index $z-fullscreen
67 | border-radius 0 !important
68 | max-width 100vw
69 | max-height 100vh
70 |
71 | .absolute-full, .fullscreen
72 | top 0
73 | right 0
74 | bottom 0
75 | left 0
76 |
77 | .fixed-center, .absolute-center
78 | top 50%
79 | left 50%
80 | transform translate(-50%, -50%)
81 |
82 | .vertical-
83 | &top
84 | vertical-align top !important
85 | &middle
86 | vertical-align middle !important
87 | &bottom
88 | vertical-align bottom !important
89 |
90 | .on-left
91 | margin-right 12px
92 | .on-right
93 | margin-left 12px
94 |
--------------------------------------------------------------------------------