Skip to content

Commit

Permalink
Merge branch 'dev' of github.com:sainf/quasar into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
sainf committed Jan 25, 2024
2 parents f32bbc3 + bb91d26 commit 5c6fef5
Show file tree
Hide file tree
Showing 15 changed files with 179 additions and 74 deletions.
2 changes: 1 addition & 1 deletion app-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"quasar": "^2.14.0",
"ts-essentials": "^9.1.2",
"typescript": "^5.2.2",
"vue": "^3.3.4",
"vue": "^3.4.15",
"vue-router": "^4.2.1",
"vuex": "^4.0.0",
"workbox-build": "^7.0.0"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/options/platform-detection.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Running on mobile means you can have this code running on a mobile device (phone
:::

## Note about SSR
When building for SSR, use only the `$q.platform` form. If you need to use the `import { Platform } from 'quasar'` (when on server-side), then you'll need to do it like this:
When building for SSR, use only the `$q.platform` form. Alternatively, when on server-side, this is one more example of how you can use it:

```js
import { Platform } from 'quasar'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ desc: (@quasar/app-vite) Tips and tricks for a Quasar server-side rendered app.
Take a look at our [Client Side Hydration](/quasar-cli-vite/developing-ssr/client-side-hydration) page. When you get hydration errors, it means the HTML rendered on the server does not match the equivalent HTML rendered on client-side. This error will appear only when developing (and NOT on production) and it definitely needs to be addressed, before you release your website. Is there some content that you can only generate on client-side? Then use [QNoSsr](/vue-components/no-ssr).

## Why doesn't importing Platform and Cookies work?
When building for SSR, use only the `$q.platform` / `$q.cookies` form. If you need to use the `import { Platform, Cookies } from 'quasar'` (when on server-side), then you’ll need to do it like this:
When building for SSR, use only the `$q.platform` / `$q.cookies` form. Alternatively, when on server-side, this is one more example of how you can use it:

```js
// example with Platform; same thing for Cookies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ desc: (@quasar/app-webpack) Tips and tricks for a Quasar server-side rendered ap
Take a look at our [Client Side Hydration](/quasar-cli-webpack/developing-ssr/client-side-hydration) page. When you get hydration errors, it means the HTML rendered on the server does not match the equivalent HTML rendered on client-side. This error will appear only when developing (and NOT on production) and it definitely needs to be addressed, before you release your website. Is there some content that you can only generate on client-side? Then use [QNoSsr](/vue-components/no-ssr).

## Why doesn't importing Platform and Cookies work?
When building for SSR, use only the `$q.platform` / `$q.cookies` form. If you need to use the `import { Platform, Cookies } from 'quasar'` (when on server-side), then you’ll need to do it like this:
When building for SSR, use only the `$q.platform` / `$q.cookies` form. Alternatively, when on server-side, this is one more example of how you can use it:

```js
// example with Platform; same thing for Cookies
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/quasar-plugins/cookies.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ With Electron version >= v1.12.2 the Cookie Plugin isn't functional in the Elect
<doc-installation plugins="Cookies" />

## Notes on SSR
When building for SSR, use only the `$q.cookies` form. If you need to use the `import { Cookies } from 'quasar'`, then you'll need to do it like this:
When building for SSR, use only the `$q.cookies` form. Alternatively, when on server-side, this is one more example of how you can use it:

```js
import { Cookies } from 'quasar'
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/quasar-plugins/dark.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Dark.toggle()

When on a SSR build:

* `import { Dark } from 'quasar'` method of using Dark mode will not error out but it will not work (won't do anything). But, you can use the [Inside of a Vue file](/quasar-plugins/dark#inside-of-a-vue-file) approach or the [Configuration](/quasar-plugins/dark#configuration) (recommended) approach.
* Import `Dark` from 'quasar' method of using Dark mode will not error out but it will not work (won't do anything). But, you can use the [Inside of a Vue file](/quasar-plugins/dark#inside-of-a-vue-file) approach or the [Configuration](/quasar-plugins/dark#configuration) (recommended) approach.
* It's preferred to avoid setting Dark mode to 'auto' for SSR builds. It's because the client dark mode preference cannot be inferred, so SSR will always render in light mode then when the client takes over, it will switch to Dark (if it will be the case). As a result, a quick flicker of the screen will occur.

## Watching for status change
Expand Down
4 changes: 2 additions & 2 deletions ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "quasar",
"version": "2.14.2",
"version": "2.14.3",
"description": "Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time",
"main": "dist/quasar.cjs.prod.js",
"module": "dist/quasar.esm.prod.js",
Expand Down Expand Up @@ -105,7 +105,7 @@
"table": "^6.8.1",
"typescript": "^4.9.5",
"uglify-es": "^3.3.9",
"vue": "^3.3.4",
"vue": "^3.4.15",
"vue-router": "^4.2.1",
"yargs": "^17.7.2"
},
Expand Down
8 changes: 4 additions & 4 deletions ui/src/components/btn-dropdown/QBtnDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import QBtnGroup from '../btn-group/QBtnGroup.js'
import QMenu from '../menu/QMenu.js'

import { getBtnDesignAttr, useBtnProps } from '../btn/use-btn.js'
import useId from '../../composables/private/use-id.js'
import { useTransitionProps } from '../../composables/private/use-transition.js'

import { createComponent } from '../../utils/private/create.js'
import { stop } from '../../utils/event.js'
import uid from '../../utils/uid.js'
import { hSlot } from '../../utils/private/render.js'

const btnPropsList = Object.keys(useBtnProps)
Expand Down Expand Up @@ -70,13 +70,13 @@ export default createComponent({

const showing = ref(props.modelValue)
const menuRef = ref(null)
const targetUid = uid()
const targetUid = useId()

const ariaAttrs = computed(() => {
const acc = {
'aria-expanded': showing.value === true ? 'true' : 'false',
'aria-haspopup': 'true',
'aria-controls': targetUid,
'aria-controls': targetUid.value,
'aria-label': props.toggleAriaLabel || proxy.$q.lang.label[ showing.value === true ? 'collapse' : 'expand' ](props.label)
}

Expand Down Expand Up @@ -170,7 +170,7 @@ export default createComponent({
props.disableDropdown !== true && Arrow.push(
h(QMenu, {
ref: menuRef,
id: targetUid,
id: targetUid.value,
class: props.contentClass,
style: props.contentStyle,
cover: props.cover,
Expand Down
7 changes: 4 additions & 3 deletions ui/src/components/expansion-item/QExpansionItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import QSlideTransition from '../slide-transition/QSlideTransition.js'
import QSeparator from '../separator/QSeparator.js'

import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
import useId from '../../composables/private/use-id.js'
import { useRouterLinkProps } from '../../composables/private/use-router-link.js'
import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js'

Expand Down Expand Up @@ -75,7 +76,7 @@ export default createComponent({
)

const blurTargetRef = ref(null)
const targetUid = uid()
const targetUid = useId()

const { show, hide, toggle } = useModelToggle({ showing })

Expand Down Expand Up @@ -143,7 +144,7 @@ export default createComponent({
return {
role: 'button',
'aria-expanded': showing.value === true ? 'true' : 'false',
'aria-controls': targetUid,
'aria-controls': targetUid.value,
'aria-label': toggleAriaLabel
}
})
Expand Down Expand Up @@ -320,7 +321,7 @@ export default createComponent({
key: 'e-content',
class: 'q-expansion-item__content relative-position',
style: contentStyle.value,
id: targetUid
id: targetUid.value
}, hSlot(slots.default)),
[ [
vShow,
Expand Down
8 changes: 4 additions & 4 deletions ui/src/components/fab/QFab.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import QBtn from '../btn/QBtn.js'
import QIcon from '../icon/QIcon.js'

import useFab, { useFabProps } from './use-fab.js'
import useId from '../../composables/private/use-id.js'
import useModelToggle, { useModelToggleProps, useModelToggleEmits } from '../../composables/private/use-model-toggle.js'

import { createComponent } from '../../utils/private/create.js'
import { hSlot, hMergeSlot } from '../../utils/private/render.js'
import { fabKey } from '../../utils/private/symbols.js'
import uid from '../../utils/uid.js'

const directions = [ 'up', 'right', 'down', 'left' ]
const alignValues = [ 'left', 'center', 'right' ]
Expand Down Expand Up @@ -49,7 +49,7 @@ export default createComponent({
setup (props, { slots }) {
const triggerRef = ref(null)
const showing = ref(props.modelValue === true)
const targetUid = uid()
const targetUid = useId()

const { proxy: { $q } } = getCurrentInstance()
const { formClass, labelProps } = useFab(props, showing)
Expand Down Expand Up @@ -77,7 +77,7 @@ export default createComponent({

const actionAttrs = computed(() => {
const attrs = {
id: targetUid,
id: targetUid.value,
role: 'menu'
}

Expand Down Expand Up @@ -149,7 +149,7 @@ export default createComponent({
fab: true,
'aria-expanded': showing.value === true ? 'true' : 'false',
'aria-haspopup': 'true',
'aria-controls': targetUid,
'aria-controls': targetUid.value,
onClick: toggle
}, getTriggerContent),

Expand Down
35 changes: 10 additions & 25 deletions ui/src/composables/private/use-field.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
import { h, ref, computed, watch, Transition, nextTick, onActivated, onDeactivated, onBeforeUnmount, onMounted, getCurrentInstance } from 'vue'

import { isRuntimeSsrPreHydration } from '../../plugins/Platform.js'

import QIcon from '../../components/icon/QIcon.js'
import QSpinner from '../../components/spinner/QSpinner.js'

import useDark, { useDarkProps } from '../../composables/private/use-dark.js'
import useId, { getId } from './use-id.js'
import useValidate, { useValidateProps } from './use-validate.js'
import useSplitAttrs from './use-split-attrs.js'

import { hSlot } from '../../utils/private/render.js'
import uid from '../../utils/uid.js'
import { prevent, stopAndPrevent } from '../../utils/event.js'
import { addFocusFn, removeFocusFn } from '../../utils/private/focus-manager.js'

function getTargetUid (val, requiredForAttr) {
return val === void 0
? (requiredForAttr === true ? `f_${ uid() }` : void 0)
: val
}

export function fieldValueIsFilled (val) {
return val !== void 0
&& val !== null
Expand Down Expand Up @@ -80,6 +72,7 @@ export function useFieldState ({ requiredForAttr = true, tagProp } = {}) {
const { props, attrs, proxy, vnode } = getCurrentInstance()

const isDark = useDark(props, proxy.$q)
const targetUid = useId(props.for, requiredForAttr)

return {
requiredForAttr,
Expand All @@ -98,9 +91,7 @@ export function useFieldState ({ requiredForAttr = true, tagProp } = {}) {
hasPopupOpen: false,

splitAttrs: useSplitAttrs(attrs, vnode),
targetUid: ref(
getTargetUid(props.for, requiredForAttr)
),
targetUid,

rootRef: ref(null),
targetRef: ref(null),
Expand Down Expand Up @@ -252,8 +243,10 @@ export default function (state) {
}))

const attributes = computed(() => {
const acc = {
for: state.targetUid.value
const acc = {}

if (state.targetUid.value) {
acc.for = state.targetUid.value
}

if (props.disable === true) {
Expand All @@ -266,7 +259,7 @@ export default function (state) {
watch(() => props.for, val => {
// don't transform targetUid into a computed
// prop as it will break SSR
state.targetUid.value = getTargetUid(val, state.requiredForAttr)
state.targetUid.value = getId(val, state.requiredForAttr)
})

function focusHandler () {
Expand Down Expand Up @@ -548,16 +541,8 @@ export default function (state) {
shouldActivate === true && props.autofocus === true && proxy.focus()
})

onMounted(() => {
if (
isRuntimeSsrPreHydration.value === true
&& state.requiredForAttr === true
&& props.for === void 0
) {
state.targetUid.value = `f_${ uid() }` // getTargetUid(void 0, true)
}

props.autofocus === true && proxy.focus()
props.autofocus === true && onMounted(() => {
proxy.focus()
})

onBeforeUnmount(() => {
Expand Down
34 changes: 34 additions & 0 deletions ui/src/composables/private/use-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ref, onMounted } from 'vue'

import uid from '../../utils/uid.js'

import { isRuntimeSsrPreHydration } from '../../plugins/Platform.js'

export function getId (val, requiredId) {
return val === void 0
? (requiredId === true ? `f_${ uid() }` : void 0)
: val
}

/**
* Returns an "id" which is a ref() that can be used as a unique identifier.
* On SSR, it takes care of generating the id on the client side (only) to
* avoid hydration errors.
*/
export default function (initialId, requiredId = true) {
if (isRuntimeSsrPreHydration.value === true) {
const id = ref(initialId)

if (requiredId === true && initialId === void 0) {
onMounted(() => {
id.value = `f_${ uid() }` // getId(void 0, true)
})
}

return id
}

return ref(
getId(initialId, requiredId)
)
}
30 changes: 3 additions & 27 deletions ui/src/plugins/Dark.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import defineReactivePlugin from '../utils/private/define-reactive-plugin.js'
import { isRuntimeSsrPreHydration } from './Platform.js'

const Plugin = defineReactivePlugin({
isActive: false,
Expand Down Expand Up @@ -38,7 +37,7 @@ const Plugin = defineReactivePlugin({
}
},

install ({ $q, onSSRHydrated, ssrContext }) {
install ({ $q, ssrContext }) {
const { dark } = $q.config

if (__QUASAR_SSR_SERVER__) {
Expand Down Expand Up @@ -66,31 +65,8 @@ const Plugin = defineReactivePlugin({

$q.dark = this

if (this.__installed === true && dark === void 0) {
return
}

this.isActive = dark === true

const initialVal = dark !== void 0 ? dark : false

if (isRuntimeSsrPreHydration.value === true) {
const ssrSet = val => {
this.__fromSSR = val
}

const originalSet = this.set

this.set = ssrSet
ssrSet(initialVal)

onSSRHydrated.push(() => {
this.set = originalSet
this.set(this.__fromSSR)
})
}
else {
this.set(initialVal)
if (this.__installed !== true) {
this.set(dark !== void 0 ? dark : false)
}
}
})
Expand Down
2 changes: 1 addition & 1 deletion utils/render-ssr-error/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"postcss": "^8.4.31",
"prismjs": "^1.29.0",
"quasar": "^2.6.0",
"vue": "^3.0.0",
"vue": "^3.4.15",
"vue-router": "^4.2.4"
}
}
Loading

0 comments on commit 5c6fef5

Please sign in to comment.