Merge branch 'primefaces:master' into fix/filter-with-columngroup-type

pull/6197/head
Uros 2024-09-10 16:23:24 +02:00 committed by GitHub
commit 9d18ca3ff8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
109 changed files with 2540 additions and 1901 deletions

View File

@ -1,5 +1,43 @@
# Changelog
## [4.0.6](https://github.com/primefaces/primevue/tree/4.0.6) (2024-09-19)
[Full Changelog](https://github.com/primefaces/primevue/compare/4.0.5...4.0.6)
**Fixed bugs:**
- animate-slidedown fails when a Tailwind prefix is used [\#6365](https://github.com/primefaces/primevue/issues/6365)
- Tree: wrong pt and classname for InputText [\#6301](https://github.com/primefaces/primevue/issues/6301)
- pt pcFilterIconContainer defects on form components [\#6286](https://github.com/primefaces/primevue/issues/6286)
- File Upload: Basic Mode does not apply buttonProps [\#6255](https://github.com/primefaces/primevue/issues/6255)
- Multiple Components: Augment vue using declare module 'vue' instead of declare module '@vue/runtime-core' (and declare module 'vue/types/vue') to avoid compilebreaks [\#6199](https://github.com/primefaces/primevue/issues/6199)
## [4.0.5](https://github.com/primefaces/primevue/tree/4.0.5) (2024-08-23)
[Full Changelog](https://github.com/primefaces/primevue/compare/4.0.4...4.0.5)
**Fixed bugs:**
- aria-hidden errors on browsers [\#6269](https://github.com/primefaces/primevue/issues/6269)
- Accordion, Button, Step, Tab: Invalid prop warnings when component object passed to as prop [\#6266](https://github.com/primefaces/primevue/issues/6266)
- Carousel: Index is undefined in PassThroughOptions [\#6264](https://github.com/primefaces/primevue/issues/6264)
- Drawer: Nested drawer dissmis [\#6262](https://github.com/primefaces/primevue/issues/6262)
- Accordion and Tabs value prop type definion extensions [\#6252](https://github.com/primefaces/primevue/issues/6252)
- DatePicker: responsiveOptions doesn't work [\#6250](https://github.com/primefaces/primevue/issues/6250)
- ScrollTop: ScrollTop button not displayed correctly when ripple effect is enabled [\#6249](https://github.com/primefaces/primevue/issues/6249)
- Stepper: activateCallback has incorrect signature [\#6225](https://github.com/primefaces/primevue/issues/6225)
- SpeedDial: Invalid aria-controls value being set in list items [\#6221](https://github.com/primefaces/primevue/issues/6221)
- InputNumber: Buttons disappear when clicked if inside of an InputGroup [\#6212](https://github.com/primefaces/primevue/issues/6212)
- IconField: 'iconfield' does not exist in type 'PrimeVuePTOptions' [\#6206](https://github.com/primefaces/primevue/issues/6206)
- DatePicker: switching to year view when modelValue is populated [\#6203](https://github.com/primefaces/primevue/issues/6203)
- Select: In case of Filter and AutoFocusFilter enabled focus is lost [\#6194](https://github.com/primefaces/primevue/issues/6194)
- InputOtp - allow NumpadEnter event [\#6182](https://github.com/primefaces/primevue/issues/6182)
- [MenuBar]: Slow performance [\#6164](https://github.com/primefaces/primevue/issues/6164)
- Dialog: [V4] When it non-fixed, it will cause the appendTo target shrink or joggled. [\#6160](https://github.com/primefaces/primevue/issues/6160)
- Menu section: PassThrough context.item has not right MenuItem entry [\#6055](https://github.com/primefaces/primevue/issues/6055)
- FileUpload v4.0.0-beta.3: Subsequent file selections no longer possible in basic mode (regression from v4.0.0-beta.2) [\#5748](https://github.com/primefaces/primevue/issues/5748)
- InputMask number repeat [\#3623](https://github.com/primefaces/primevue/issues/3623)
## [4.0.4](https://github.com/primefaces/primevue/tree/4.0.4) (2024-08-02)
[Full Changelog](https://github.com/primefaces/primevue/compare/4.0.3...4.0.4)

View File

@ -1,6 +1,6 @@
{
"id": 64,
"content": "Sakai Template v4 is out!",
"linkText": "View Demo",
"linkHref": "https://sakai.primevue.org"
"id": 65,
"content": "Summer Sale: Up to 50% Off 🛍️",
"linkText": "Visit Store",
"linkHref": "https://primefaces.org/store"
}

View File

@ -6,7 +6,7 @@
<div class="flex-1 border border-surface rounded-xl lg:rounded-2xl p-6 min-w-80">
<span class="text-surface-600 dark:text-surface-400 font-semibold">{{ detail.title }}</span>
<div class="text-surface-900 dark:text-surface-0 text-4xl font-semibold mt-4 mb-5">
<span :class="{ 'text-surface-600 dark:text-surface-400 line-through mr-4': license.showDiscount }">{{ detail.price }}</span>
<span :class="{ 'text-muted-color line-through mr-4': license.showDiscount }">{{ detail.price }}</span>
<span v-if="license.showDiscount">{{ detail.discount }}</span>
</div>
<div class="flex flex-col gap-2 mb-5">

View File

@ -210,7 +210,7 @@
"name": "value",
"optional": true,
"readonly": false,
"type": "null | string | string[]",
"type": "null | string | number | string[] | number[]",
"default": "null",
"description": "Value of the active panel or an array of values in multiple mode."
},
@ -637,7 +637,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "DIV",
"description": "Use to change the HTML tag of root element."
},
@ -924,7 +924,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "BUTTON",
"description": "Use to change the HTML tag of root element."
},
@ -1209,7 +1209,7 @@
"name": "value",
"optional": false,
"readonly": false,
"type": "string",
"type": "undefined | string | number",
"default": "",
"description": "Unique value of item."
},
@ -1225,7 +1225,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "DIV",
"description": "Use to change the HTML tag of root element."
},
@ -2625,7 +2625,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached.\nSpecial keywords are 'body' for document body and 'self' for the element itself."
},
@ -5644,7 +5644,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "BUTTON",
"description": "Use to change the HTML tag of root element."
},
@ -7119,6 +7119,38 @@
"type": "boolean",
"default": "false",
"description": "Current highlighted state of the indicator as a boolean."
},
{
"name": "index",
"optional": false,
"readonly": false,
"type": "number",
"default": "",
"description": "Index of the item as a number."
},
{
"name": "active",
"optional": false,
"readonly": false,
"type": "boolean",
"default": "false",
"description": "Current active state of the item as a boolean."
},
{
"name": "start",
"optional": false,
"readonly": false,
"type": "boolean",
"default": "false",
"description": "Current start state of the item as a boolean."
},
{
"name": "end",
"optional": false,
"readonly": false,
"type": "boolean",
"default": "false",
"description": "Current end state of the item as a boolean."
}
],
"methods": []
@ -8215,7 +8247,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached. Special keywords are 'body' for document body and 'self' for the element itself."
},
@ -8911,7 +8943,7 @@
"name": "plugins",
"optional": true,
"readonly": false,
"type": "any",
"type": "any[]",
"default": "",
"description": "Used to custom plugins of the chart."
},
@ -10571,7 +10603,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached. Special keywords are 'body' for document body and 'self' for the element itself."
},
@ -12976,6 +13008,13 @@
"type": "any",
"default": ""
},
{
"name": "iconfield",
"optional": true,
"readonly": false,
"type": "any",
"default": ""
},
{
"name": "image",
"optional": true,
@ -15091,7 +15130,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},
@ -16818,7 +16857,7 @@
"description": "Collection of active filters"
},
{
"name": "columWidths",
"name": "columnWidths",
"optional": false,
"readonly": false,
"type": "string[]",
@ -21106,7 +21145,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},
@ -22659,7 +22698,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the dialog gets attached."
},
@ -22872,6 +22911,19 @@
"returnType": "void",
"description": "Fired when a dialog gets unmaximized."
},
{
"name": "dragstart",
"parameters": [
{
"name": "event",
"optional": false,
"type": "Event",
"description": "Browser event."
}
],
"returnType": "void",
"description": "Fired when a dialog drag begins."
},
{
"name": "dragend",
"parameters": [
@ -26546,22 +26598,6 @@
"default": "",
"description": "Used to pass attributes to the empty's DOM element."
},
{
"name": "pcMessages",
"optional": true,
"readonly": false,
"type": "any",
"default": "",
"description": "Used to pass attributes to the messages' DOM element."
},
{
"name": "pcButton",
"optional": true,
"readonly": false,
"type": "any",
"default": "",
"description": "Used to pass attributes to the basic mode's button's DOM element."
},
{
"name": "hooks",
"optional": true,
@ -26610,7 +26646,7 @@
"name": "messages",
"optional": false,
"readonly": false,
"type": "any[]",
"type": "null | string[]",
"default": "",
"description": "Current messages."
},
@ -29184,7 +29220,7 @@
}
},
"iconfield": {
"description": "IconField wraps an input and an icon.\n\n[Live Demo](https://www.primevue.org/inputtext/)",
"description": "IconField wraps an input and an icon.\n\n[Live Demo](https://www.primevue.org/iconfield/)",
"components": {
"default": {
"description": "IconField is used to select a boolean value.",
@ -37313,7 +37349,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},
@ -40345,7 +40381,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached. Special keywords are 'body' for document body and 'self' for the element itself."
},
@ -45882,7 +45918,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},
@ -47739,7 +47775,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},
@ -51584,7 +51620,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},
@ -54623,7 +54659,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached.\nSpecial keywords are 'body' for document body and 'self' for the element itself."
},
@ -55916,7 +55952,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "BUTTON",
"description": "Use to change the HTML tag of root element."
},
@ -56689,7 +56725,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "BUTTON",
"description": "Use to change the HTML tag of root element."
},
@ -56739,7 +56775,7 @@
{
"name": "scope",
"optional": false,
"type": "{\n \t <span class=\"ml-3 doc-option-parameter-name\">active</span>: <span class=\"doc-option-parameter-type\">boolean</span>, <span class=\"doc-option-parameter-type\">// Whether the step is active.</span>\n \t <span class=\"ml-3 doc-option-parameter-name\">value</span>: <span class=\"doc-option-parameter-type\">undefined</span>, <span class=\"doc-option-parameter-type\">// Value of step.</span>\n \t <span class=\"ml-3 doc-option-parameter-name\">a11yAttrs</span>: <span class=\"doc-option-parameter-type\">any</span>, <span class=\"doc-option-parameter-type\">// A11t attributes</span>\n \t <span class=\"ml-3 doc-option-parameter-name\">activateCallback</span>: <span class=\"doc-option-parameter-type\">() &rArr; void</span>, <span class=\"doc-option-parameter-type\">// Click function.</span>\n}"
"type": "{\n \t <span class=\"ml-3 doc-option-parameter-name\">active</span>: <span class=\"doc-option-parameter-type\">boolean</span>, <span class=\"doc-option-parameter-type\">// Whether the step is active.</span>\n \t <span class=\"ml-3 doc-option-parameter-name\">value</span>: <span class=\"doc-option-parameter-type\">undefined</span>, <span class=\"doc-option-parameter-type\">// Value of step.</span>\n \t <span class=\"ml-3 doc-option-parameter-name\">a11yAttrs</span>: <span class=\"doc-option-parameter-type\">any</span>, <span class=\"doc-option-parameter-type\">// A11t attributes</span>\n \t <span class=\"ml-3 doc-option-parameter-name\">activateCallback</span>: <span class=\"doc-option-parameter-type\">(<span class=\"doc-option-parameter-name\">value</span>: undefined) &rArr; void</span>, <span class=\"doc-option-parameter-type\">// Click function.</span>\n}"
}
],
"returnType": "VNode<RendererNode, RendererElement, Object>[]",
@ -57896,6 +57932,14 @@
"default": "",
"description": "Style class to add when leave animation is completed."
},
{
"name": "hiddenClass",
"optional": true,
"readonly": false,
"type": "string",
"default": "",
"description": "Special class name to hide an element, only used in slide animation."
},
{
"name": "hideOnOutsideClick",
"optional": true,
@ -58137,7 +58181,7 @@
"name": "value",
"optional": false,
"readonly": false,
"type": "string",
"type": "string | number",
"default": "",
"description": "Value of tab."
},
@ -58153,7 +58197,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "BUTTON",
"description": "Use to change the HTML tag of root element."
},
@ -59311,7 +59355,7 @@
"name": "value",
"optional": false,
"readonly": false,
"type": "string",
"type": "string | number",
"default": "",
"description": "Value of tabpanel."
},
@ -59319,7 +59363,7 @@
"name": "as",
"optional": true,
"readonly": false,
"type": "string",
"type": "string | Component",
"default": "DIV",
"description": "Use to change the HTML tag of root element."
},
@ -59993,7 +60037,7 @@
"name": "value",
"optional": false,
"readonly": false,
"type": "string",
"type": "string | number",
"default": "",
"description": "Value of the active tab."
},
@ -61805,7 +61849,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},
@ -65205,7 +65249,7 @@
"description": "Used to pass attributes to the IconField component."
},
{
"name": "pcFilter",
"name": "pcFilterInput",
"optional": true,
"readonly": false,
"type": "any",
@ -66521,7 +66565,7 @@
"name": "appendTo",
"optional": true,
"readonly": false,
"type": "HintedString<\"body\" | \"self\"> | HTMLElement",
"type": "HTMLElement | HintedString<\"body\" | \"self\">",
"default": "body",
"description": "A valid query selector or an HTMLElement to specify where the overlay gets attached."
},

View File

@ -7,9 +7,9 @@
<template #list="slotProps">
<div class="flex flex-col">
<div v-for="(item, index) in slotProps.items" :key="index">
<div class="flex flex-col sm:flex-row sm:items-center p-6 gap-4" :class="{ 'border-t border-surface-200 dark:border-surface-700': index !== 0 }">
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
<div class="md:w-40 relative">
<img class="block xl:block mx-auto rounded w-full" :src="`https://primefaces.org/cdn/primevue/images/product/${item.image}`" :alt="item.name" />
<img class="rounded w-36" :src="`https://primefaces.org/cdn/primevue/images/product/${item.image}`" :alt="item.name" />
<div class="dark:bg-surface-900 absolute rounded-border" style="left: 4px; top: 4px">
<Tag :value="item.inventoryStatus" :severity="getSeverity(item)"></Tag>
</div>

View File

@ -318,7 +318,7 @@ export default {
<template #list="slotProps">
<div class="flex flex-col">
<div v-for="(item, index) in slotProps.items" :key="index"">
<div v-for="(item, index) in slotProps.items" :key="index">
<div class="flex flex-col sm:flex-row sm:items-center p-6 gap-4" :class="{ 'border-t border-surface-200 dark:border-surface-700': index !== 0 }">
<div class="md:w-40 relative">
<img class="block xl:block mx-auto rounded w-full" :src="\`https://primefaces.org/cdn/primevue/images/product/\${item.image}\`" :alt="item.name" />

View File

@ -1,9 +1,10 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Uploading implementation can be overridden by enabling <i>customUpload</i> property and defining a custom <i>uploader</i> handler event.</p>
<p>Uploading implementation can be overridden by enabling <i>customUpload</i> property. This sample, displays the image on the client side with a grayscale filter.</p>
</DocSectionText>
<div class="card flex justify-center">
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
<div class="card flex flex-col items-center gap-6">
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
</div>
<DocSectionCode :code="code" />
</template>
@ -12,30 +13,37 @@
export default {
data() {
return {
src: null,
code: {
basic: `
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
`,
options: `
<template>
<div class="card flex justify-center">
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
<div class="card flex flex-col items-center gap-6">
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
</div>
</template>
<script>
export default {
data() {
return {
src: null
}
},
methods: {
async customBase64Uploader(event) {
onFileSelect(event) {
const file = event.files[0];
const reader = new FileReader();
let blob = await fetch(file.objectURL).then((r) => r.blob()); //blob:url
reader.readAsDataURL(blob);
reader.onloadend = function () {
const base64data = reader.result;
reader.onload = async (e) => {
this.src = e.target.result;
};
reader.readAsDataURL(file);
}
}
};
@ -43,39 +51,42 @@ export default {
`,
composition: `
<template>
<div class="card flex justify-center">
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
<div class="card flex flex-col items-center gap-6">
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
</div>
</template>
<script setup>
const customBase64Uploader = async (event) => {
import { ref } from "vue";
const src = ref(null);
function onFileSelect(event) {
const file = event.files[0];
const reader = new FileReader();
let blob = await fetch(file.objectURL).then((r) => r.blob()); //blob:url
reader.readAsDataURL(blob);
reader.onloadend = function () {
const base64data = reader.result;
reader.onload = async (e) => {
src.value = e.target.result;
};
};
reader.readAsDataURL(file);
}
<\/script>
`
}
};
},
methods: {
async customBase64Uploader(event) {
onFileSelect(event) {
const file = event.files[0];
const reader = new FileReader();
let blob = await fetch(file.objectURL).then((r) => r.blob()); //blob:url
reader.readAsDataURL(blob);
reader.onloadend = function () {
const base64data = reader.result;
reader.onload = async (e) => {
this.src = e.target.result;
};
reader.readAsDataURL(file);
}
}
};

View File

@ -41,9 +41,7 @@ export default {
<img :src="slotProps.item.itemImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
<template #thumbnail="slotProps">
<template #thumbnail="slotProps">
<img :src="slotProps.item.thumbnailImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
<img :src="slotProps.item.thumbnailImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
</Galleria>
`,
@ -55,9 +53,7 @@ export default {
<img :src="slotProps.item.itemImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
<template #thumbnail="slotProps">
<template #thumbnail="slotProps">
<img :src="slotProps.item.thumbnailImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
<img :src="slotProps.item.thumbnailImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
</Galleria>
</div>
@ -96,9 +92,7 @@ export default {
<img :src="slotProps.item.itemImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
<template #thumbnail="slotProps">
<template #thumbnail="slotProps">
<img :src="slotProps.item.thumbnailImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
<img :src="slotProps.item.thumbnailImageSrc" :alt="slotProps.item.alt" style="width: 100%; display: block" />
</template>
</Galleria>
</div>

View File

@ -1,7 +1,7 @@
<template>
<DocSectionText id="accessibility" label="Accessibility" v-bind="$attrs">
<h3>Screen Reader</h3>
<p>IconField and InputIcon does not require any roles and attributes.</p>
<p>IconField and InputIcon do not require any roles and attributes.</p>
<h3>Keyboard Support</h3>
<p>Components does not include any interactive elements.</p>

View File

@ -1,7 +1,7 @@
<template>
<DocSectionText id="accessibility" label="Accessibility" v-bind="$attrs">
<h3>Screen Reader</h3>
<p>InputGroup and InputGroupAddon does not require any roles and attributes.</p>
<p>InputGroup and InputGroupAddon do not require any roles and attributes.</p>
<h3>Keyboard Support</h3>
<p>Component does not include any interactive elements.</p>

View File

@ -56,7 +56,7 @@ export default {
],
code: {
basic: `
<Button type="button" icon="pi pi-image" label="Image" @click="toggle" />
<Button type="button" icon="pi pi-share-alt" label="Share" @click="toggle" />
<Popover ref="op">
<div class="flex flex-col gap-4 w-[25rem]">
@ -98,7 +98,7 @@ export default {
options: `
<template>
<div class="card flex justify-center">
<Button type="button" icon="pi pi-image" label="Image" @click="toggle" />
<Button type="button" icon="pi pi-share-alt" label="Share" @click="toggle" />
<Popover ref="op">
<div class="flex flex-col gap-4 w-[25rem]">
@ -161,7 +161,7 @@ export default {
composition: `
<template>
<div class="card flex justify-center">
<Button type="button" icon="pi pi-image" label="Image" @click="toggle" />
<Button type="button" icon="pi pi-share-alt" label="Share" @click="toggle" />
<Popover ref="op">
<div class="flex flex-col gap-4 w-[25rem]">

View File

@ -1,34 +1,55 @@
<template>
<DocSectionText v-bind="$attrs">
<p>An example that displays a DataTable inside a popup to select an item.</p>
<p>Place the Popover outside of the data iteration components to avoid rendering it multiple times.</p>
</DocSectionText>
<div class="card flex flex-col items-center gap-4">
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
<div class="card">
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
<Column field="id" header="Id" class="w-1/6"></Column>
<Column field="code" header="Code" class="w-1/6"></Column>
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
<Column field="price" header="Price" sortable class="w-1/6">
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
</Column>
<Column header="Image" class="w-1/6">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column header="Details" class="w-1/6">
<template #body="slotProps">
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
</template>
</Column>
</DataTable>
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
<div class="relative">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${selectedProduct.image}`" :alt="selectedProduct.name" class="w-full sm:w-80" />
<Popover ref="op">
<div v-if="selectedProduct" class="rounded flex flex-col">
<div class="flex justify-center rounded">
<div class="relative mx-auto">
<img class="rounded w-44 sm:w-64" :src="`https://primefaces.org/cdn/primevue/images/product/${selectedProduct.image}`" :alt="selectedProduct.name" />
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
</div>
</div>
<div class="pt-4">
<div class="flex flex-row justify-between items-start gap-2 mb-4">
<div>
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
<div class="text-lg font-medium mt-1">{{ selectedProduct.name }}</div>
</div>
<div class="bg-surface-100 p-1" style="border-radius: 30px">
<div class="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2" style="border-radius: 30px; box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)">
<span class="text-surface-900 font-medium text-sm">{{ selectedProduct.rating }}</span>
<i class="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div class="flex gap-2">
<Button icon="pi pi-shopping-cart" :label="`Buy Now | \$${selectedProduct.price}`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
</div>
</div>
</div>
<div class="flex items-center justify-between mt-4 mb-2">
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
</div>
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
</div>
<Popover ref="op" appendTo="body">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :paginator="true" :rows="5" @row-select="onProductSelect">
<Column field="name" header="Name" sortable style="min-width: 12rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
</Column>
</DataTable>
</Popover>
</div>
<DocSectionCode :code="code" :service="['ProductService']" />
@ -43,67 +64,103 @@ export default {
selectedProduct: null,
code: {
basic: `
<Toast />
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
<Column field="id" header="Id" class="w-1/6"></Column>
<Column field="code" header="Code" class="w-1/6"></Column>
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
<Column field="price" header="Price" sortable class="w-1/6">
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
</Column>
<Column header="Image" class="w-1/6">
<template #body="slotProps">
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${slotProps.data.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column header="Details" class="w-1/6">
<template #body="slotProps">
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
</template>
</Column>
</DataTable>
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
<div class="relative">
<img :src="\`/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" class="w-16 shadow-sm" class="w-full sm:w-80" />
<Popover ref="op">
<div v-if="selectedProduct" class="rounded flex flex-col">
<div class="flex justify-center rounded">
<div class="relative mx-auto">
<img class="rounded w-44 sm:w-64" :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" />
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
</div>
</div>
<div class="pt-4">
<div class="flex flex-row justify-between items-start gap-2 mb-4">
<div>
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
<div class="text-lg font-medium mt-1">{{ selectedProduct.name }}</div>
</div>
<div class="bg-surface-100 p-1" style="border-radius: 30px">
<div class="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2" style="border-radius: 30px; box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)">
<span class="text-surface-900 font-medium text-sm">{{ selectedProduct.rating }}</span>
<i class="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div class="flex gap-2">
<Button icon="pi pi-shopping-cart" :label="\`Buy Now | \\$\${selectedProduct.price}\`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
</div>
</div>
</div>
<div class="flex items-center justify-between mt-4 mb-2">
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
</div>
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
</div>
<Popover ref="op" appendTo="body">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :paginator="true" :rows="5" @row-select="onProductSelect">
<Column field="name" header="Name" sortable style="width: 50%"></Column>
<Column header="Image" style="width: 20%">
<template #body="slotProps">
<img :src="\`/images/product/\${selectedProduct.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column field="price" header="Price" sortable style="width: 30%">
<template #body="slotProps">
$ {{ slotProps.data.price }}
</template>
</Column>
</DataTable>
</Popover>
`,
options: `
<template>
<div class="card flex flex-col items-center gap-4">
<Toast />
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
<div class="card">
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
<Column field="id" header="Id" class="w-1/6"></Column>
<Column field="code" header="Code" class="w-1/6"></Column>
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
<Column field="price" header="Price" sortable class="w-1/6">
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
</Column>
<Column header="Image" class="w-1/6">
<template #body="slotProps">
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${slotProps.data.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column header="Details" class="w-1/6">
<template #body="slotProps">
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
</template>
</Column>
</DataTable>
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
<div class="relative">
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" class="w-full sm:w-80" />
<Popover ref="op">
<div v-if="selectedProduct" class="rounded flex flex-col">
<div class="flex justify-center rounded">
<div class="relative mx-auto">
<img class="rounded w-44 sm:w-64" :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" />
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
</div>
</div>
<div class="pt-4">
<div class="flex flex-row justify-between items-start gap-2 mb-4">
<div>
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
<div class="text-lg font-medium mt-1">{{ selectedProduct.name }}</div>
</div>
<div class="bg-surface-100 p-1" style="border-radius: 30px">
<div class="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2" style="border-radius: 30px; box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)">
<span class="text-surface-900 font-medium text-sm">{{ selectedProduct.rating }}</span>
<i class="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div class="flex gap-2">
<Button icon="pi pi-shopping-cart" :label="\`Buy Now | \\$\${selectedProduct.price}\`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
</div>
</div>
</div>
<div class="flex items-center justify-between mt-4 mb-2">
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
</div>
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
</div>
<Popover ref="op" appendTo="body">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :paginator="true" :rows="5" @row-select="onProductSelect">
<Column field="name" header="Name" sortable style="min-width: 12rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps">
$ {{ slotProps.data.price }}
</template>
</Column>
</DataTable>
</Popover>
</div>
</template>
@ -119,17 +176,39 @@ export default {
};
},
mounted() {
ProductService.getProductsSmall()
.then((data) => (this.products = data))
.then(() => (this.selectedProduct = this.products[0]));
ProductService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
toggle(event) {
this.$refs.op.toggle(event);
},
onProductSelect(event) {
displayProduct(event, product) {
this.$refs.op.hide();
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: event.data.name, life: 3000 });
if (this.selectedProduct?.id === product.id) {
this.selectedProduct = null;
} else {
this.selectedProduct = product;
this.$nextTick(() => {
this.$refs.op.show(event);
});
}
},
hidePopover() {
this.$refs.op.hide();
},
getSeverity(product) {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
}
}
};
@ -137,62 +216,102 @@ export default {
`,
composition: `
<template>
<div class="card flex flex-col items-center gap-4">
<Toast />
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
<div class="card">
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
<Column field="id" header="Id" class="w-1/6"></Column>
<Column field="code" header="Code" class="w-1/6"></Column>
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
<Column field="price" header="Price" sortable class="w-1/6">
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
</Column>
<Column header="Image" class="w-1/6">
<template #body="slotProps">
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${slotProps.data.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column header="Details" class="w-1/6">
<template #body="slotProps">
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
</template>
</Column>
</DataTable>
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
<div class="relative">
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" class="w-full sm:w-80" />
<Popover ref="op">
<div v-if="selectedProduct" class="rounded flex flex-col">
<div class="flex justify-center rounded">
<div class="relative mx-auto">
<img class="rounded w-44 sm:w-64" :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" />
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
</div>
</div>
<div class="pt-4">
<div class="flex flex-row justify-between items-start gap-2 mb-4">
<div>
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
<div class="text-lg font-medium mt-1">{{ selectedProduct.name }}</div>
</div>
<div class="bg-surface-100 p-1" style="border-radius: 30px">
<div class="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2" style="border-radius: 30px; box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)">
<span class="text-surface-900 font-medium text-sm">{{ selectedProduct.rating }}</span>
<i class="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div class="flex gap-2">
<Button icon="pi pi-shopping-cart" :label="\`Buy Now | \\$\${selectedProduct.price}\`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
</div>
</div>
</div>
<div class="flex items-center justify-between mt-4 mb-2">
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
</div>
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
</div>
<Popover ref="op" appendTo="body">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :paginator="true" :rows="5" @row-select="onProductSelect">
<Column field="name" header="Name" sortable style="min-width: 12rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps">
$ {{ slotProps.data.price }}
</template>
</Column>
</DataTable>
</Popover>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { ref, onMounted, nextTick } from "vue";
import { useToast } from "primevue/usetoast";
import { ProductService } from '@/service/ProductService';
onMounted(() => {
ProductService.getProductsSmall()
.then((data) => (products.value = data))
.then(() => (selectedProduct.value = products.value[0]));
ProductService.getProductsSmall().then((data) => (products.value = data));
});
const toast = useToast();
const op = ref();
const products = ref();
const selectedProduct = ref();
const toggle = (event) => {
op.value.toggle(event);
};
const onProductSelect = (event) => {
const displayProduct = (event, product) => {
op.value.hide();
toast.add({ severity: 'info', summary: 'Product Selected', detail: event.data.name, life: 3000 });
if (selectedProduct.value?.id === product.id) {
selectedProduct.value = null;
} else {
selectedProduct.value = product;
nextTick(() => {
op.value.show(event);
});
}
}
const hidePopover = () => {
op.value.hide();
}
const getSeverity = (product) => {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
}
<\/script>
`,
@ -216,17 +335,39 @@ const onProductSelect = (event) => {
};
},
mounted() {
ProductService.getProductsSmall()
.then((data) => (this.products = data))
.then(() => (this.selectedProduct = this.products[0]));
ProductService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
toggle(event) {
this.$refs.op.toggle(event);
},
onProductSelect(event) {
displayProduct(event, product) {
this.$refs.op.hide();
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: event.data.name, life: 3000 });
if (this.selectedProduct?.id === product.id) {
this.selectedProduct = null;
} else {
this.selectedProduct = product;
this.$nextTick(() => {
this.$refs.op.show(event);
});
}
},
hidePopover() {
this.$refs.op.hide();
},
getSeverity(product) {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
}
}
};

View File

@ -0,0 +1,165 @@
<template>
<DocSectionText v-bind="$attrs">
<p>In this sample, data is retrieved from the content inside the popover.</p>
</DocSectionText>
<div class="card flex justify-center">
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
<Popover ref="op">
<div class="flex flex-col gap-4">
<div>
<span class="font-medium block mb-2">Team Members</span>
<ul class="list-none p-0 m-0 flex flex-col">
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
<img :src="`https://primefaces.org/cdn/primevue/images/avatar/${member.image}`" style="width: 32px" />
<div>
<span class="font-medium">{{ member.name }}</span>
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
</div>
</li>
</ul>
</div>
</div>
</Popover>
</div>
<DocSectionCode :code="code" />
</template>
<script>
export default {
data() {
return {
selectedMember: null,
members: [
{ name: 'Amy Elsner', image: 'amyelsner.png', email: 'amy@email.com', role: 'Owner' },
{ name: 'Bernardo Dominic', image: 'bernardodominic.png', email: 'bernardo@email.com', role: 'Editor' },
{ name: 'Ioni Bowcher', image: 'ionibowcher.png', email: 'ioni@email.com', role: 'Viewer' }
],
code: {
basic: `
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
<Popover ref="op">
<div class="flex flex-col gap-4">
<div>
<span class="font-medium block mb-2">Team Members</span>
<ul class="list-none p-0 m-0 flex flex-col">
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
<img :src="\`https://primefaces.org/cdn/primevue/images/avatar/\${member.image}\`" style="width: 32px" />
<div>
<span class="font-medium">{{ member.name }}</span>
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
</div>
</li>
</ul>
</div>
</div>
</Popover>
`,
options: `
<template>
<div class="card flex justify-center">
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
<Popover ref="op">
<div class="flex flex-col gap-4">
<div>
<span class="font-medium block mb-2">Team Members</span>
<ul class="list-none p-0 m-0 flex flex-col">
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
<img :src="\`https://primefaces.org/cdn/primevue/images/avatar/\${member.image}\`" style="width: 32px" />
<div>
<span class="font-medium">{{ member.name }}</span>
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
</div>
</li>
</ul>
</div>
</div>
</Popover>
</div>
</template>
<script>
export default {
data() {
return {
selectedMember: null,
members: [
{ name: 'Amy Elsner', image: 'amyelsner.png', email: 'amy@email.com', role: 'Owner' },
{ name: 'Bernardo Dominic', image: 'bernardodominic.png', email: 'bernardo@email.com', role: 'Editor' },
{ name: 'Ioni Bowcher', image: 'ionibowcher.png', email: 'ioni@email.com', role: 'Viewer' }
]
}
},
methods: {
toggle(event) {
this.$refs.op.toggle(event);
},
selectMember(member) {
this.selectedMember = member;
this.$refs.op.hide();
}
}
};
<\/script>
`,
composition: `
<template>
<div class="card flex justify-center">
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
<Popover ref="op">
<div class="flex flex-col gap-4">
<div>
<span class="font-medium block mb-2">Team Members</span>
<ul class="list-none p-0 m-0 flex flex-col">
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
<img :src="\`https://primefaces.org/cdn/primevue/images/avatar/\${member.image}\`" style="width: 32px" />
<div>
<span class="font-medium">{{ member.name }}</span>
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
</div>
</li>
</ul>
</div>
</div>
</Popover>
</div>
</template>
<script setup>
import { ref } from "vue";
const op = ref();
const selectedMember = ref(null);
const members = ref([
{ name: 'Amy Elsner', image: 'amyelsner.png', email: 'amy@email.com', role: 'Owner' },
{ name: 'Bernardo Dominic', image: 'bernardodominic.png', email: 'bernardo@email.com', role: 'Editor' },
{ name: 'Ioni Bowcher', image: 'ionibowcher.png', email: 'ioni@email.com', role: 'Viewer' }
]);
const toggle = (event) => {
op.value.toggle(event);
}
const selectMember = (member) => {
selectedMember.value = member;
op.value.hide();
}
<\/script>
`
}
};
},
methods: {
toggle(event) {
this.$refs.op.toggle(event);
},
selectMember(member) {
this.selectedMember = member;
this.$refs.op.hide();
}
}
};
</script>

View File

@ -4,14 +4,30 @@
Classes to apply during enter and leave animations are specified using the <i>enterFromClass</i>, <i>enterActiveClass</i>, <i>enterToClass</i>, <i>leaveFromClass</i>, <i>leaveActiveClass</i>,<i>leaveToClass</i>properties. In addition in
case the target is an overlay, <i>hideOnOutsideClick</i> would be handy to hide the target if outside of the popup is clicked.
</p>
<p>First example uses a custom fade animation, and second one uses animate-slide from <NuxtLink to="/tailwind/#animations">tailwind-primeui</NuxtLink> plugin.</p>
</DocSectionText>
<div class="card flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="Show" class="mr-2" />
<Button v-styleclass="{ selector: '.box', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="Hide" severity="secondary" />
<div class="card flex items-center justify-center gap-8">
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box1', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="FadeIn" class="mr-2" />
<Button v-styleclass="{ selector: '.box1', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="FadeOut" severity="secondary" />
</div>
<div class="h-32">
<div class="my-hidden animate-duration-500 box1">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Custom</div>
</div>
</div>
</div>
<div class="my-hidden animate-duration-500 box">
<div class="flex bg-green-500 text-white items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box2', enterFromClass: 'hidden', enterActiveClass: 'animate-slidedown' }" label="SlideDown" class="mr-2" />
<Button v-styleclass="{ selector: '.box2', leaveActiveClass: 'animate-slideup', leaveToClass: 'hidden' }" label="SlideUp" severity="secondary" />
</div>
<div class="h-32">
<div class="hidden animate-duration-500 box2 overflow-hidden">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
</div>
</div>
</div>
</div>
<DocSectionCode :code="code" />
@ -23,21 +39,55 @@ export default {
return {
code: {
basic: `
<Button v-styleclass="{ selector: '.box', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="Show" class="mr-2" />
<Button v-styleclass="{ selector: '.box', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="Hide" severity="secondary" />
<div class="my-hidden animate-duration-500 box">
<div class="flex bg-green-500 text-white items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
<div class="card flex items-center justify-center gap-8">
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box1', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="FadeIn" class="mr-2" />
<Button v-styleclass="{ selector: '.box1', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="FadeOut" severity="secondary" />
</div>
<div class="h-32">
<div class="my-hidden animate-duration-500 box1">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Custom</div>
</div>
</div>
</div>
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box2', enterFromClass: 'hidden', enterActiveClass: 'animate-slidedown' }" label="SlideDown" class="mr-2" />
<Button v-styleclass="{ selector: '.box2', leaveActiveClass: 'animate-slideup', leaveToClass: 'hidden' }" label="SlideUp" severity="secondary" />
</div>
<div class="h-32">
<div class="hidden animate-duration-500 box2 overflow-hidden">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
</div>
</div>
</div>
</div>
`,
options: `
<template>
<div class="card flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="Show" class="mr-2" />
<Button v-styleclass="{ selector: '.box', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="Hide" severity="secondary" />
<div class="card flex items-center justify-center gap-8">
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box1', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="FadeIn" class="mr-2" />
<Button v-styleclass="{ selector: '.box1', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="FadeOut" severity="secondary" />
</div>
<div class="h-32">
<div class="my-hidden animate-duration-500 box1">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Custom</div>
</div>
</div>
</div>
<div class="my-hidden animate-duration-500 box">
<div class="flex bg-green-500 text-white items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box2', enterFromClass: 'hidden', enterActiveClass: 'animate-slidedown' }" label="SlideDown" class="mr-2" />
<Button v-styleclass="{ selector: '.box2', leaveActiveClass: 'animate-slideup', leaveToClass: 'hidden' }" label="SlideUp" severity="secondary" />
</div>
<div class="h-32">
<div class="hidden animate-duration-500 box2 overflow-hidden">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
</div>
</div>
</div>
</div>
</template>
@ -79,13 +129,28 @@ export default {
`,
composition: `
<template>
<div class="card flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="Show" class="mr-2" />
<Button v-styleclass="{ selector: '.box', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="Hide" severity="secondary" />
<div class="card flex items-center justify-center gap-8">
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box1', enterFromClass: 'my-hidden', enterActiveClass: 'my-fadein' }" label="FadeIn" class="mr-2" />
<Button v-styleclass="{ selector: '.box1', leaveActiveClass: 'my-fadeout', leaveToClass: 'my-hidden' }" label="FadeOut" severity="secondary" />
</div>
<div class="h-32">
<div class="my-hidden animate-duration-500 box1">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Custom</div>
</div>
</div>
</div>
<div class="my-hidden animate-duration-500 box">
<div class="flex bg-green-500 text-white items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
<div class="flex flex-col items-center">
<div>
<Button v-styleclass="{ selector: '.box2', enterFromClass: 'hidden', enterActiveClass: 'animate-slidedown' }" label="SlideDown" class="mr-2" />
<Button v-styleclass="{ selector: '.box2', leaveActiveClass: 'animate-slideup', leaveToClass: 'hidden' }" label="SlideUp" severity="secondary" />
</div>
<div class="h-32">
<div class="hidden animate-duration-500 box2 overflow-hidden">
<div class="flex bg-primary text-primary-contrast items-center justify-center py-4 rounded-md mt-4 font-bold w-32 h-32">Content</div>
</div>
</div>
</div>
</div>
</template>

View File

@ -39,12 +39,12 @@ app.use(PrimeVue, {
},
code2: {
basic: `
<Button label="Toggle Color Scheme" @click="toggleColorScheme()" />
<Button label="Toggle Dark Mode" @click="toggleDarkMode()" />
`
},
code3: {
basic: `
const toggleColorScheme() {
function toggleDarkMode() {
const element = document.querySelector('html');
element.classList.toggle('my-app-dark');
}

View File

@ -4,11 +4,11 @@
The <i>@layer</i> is a standard CSS feature to define cascade layers for a customizable order of precedence. If you need to become more familiar with layers, visit the documentation at
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@layer" class="doc-link">MDN</a> to begin with. In styled mode, when the <i>cssLayer</i> option is enabled at theme configuration, PrimeVue wraps the built-in style classes under
the <i>primevue</i> cascade layer to make the library styles easy to override. CSS in your app without a layer has the highest CSS specificity, so you'll be able to override styles regardless of the location or how strong a class is
written. The <i>cssLayer</i> is disabled by default to avoid compatibility issues with 3rd party CSS libraries which requires a layer configuration for compatibility that is discussed in the next reset section.
written. The <i>cssLayer</i> is disabled by default to avoid compatibility issues with 3rd party CSS libraries which require a layer configuration for compatibility that is discussed in the next reset section.
</p>
<p>
For example, let's assume you need to remove the rounded borders of the ToggleSwitch component defined by the theme in use. In order to achieve this, <i>.p-toggleswitch .p-toggleswitch-slider</i> selector needs to be overriden. Without
the layers, we'd have to write a stronger css or use <i>!important</i> however, with layers, this does not present an issue as your CSS can always override PrimeVue with a more straightforward class name such as <i>my-switch-slider</i>.
the layers, we'd have to write a stronger css or use <i>!important</i>, however, with layers, this does not present an issue as your CSS can always override PrimeVue with a more straightforward class name such as <i>my-switch-slider</i>.
Another advantage of this approach is that it does not force you to figure out the built-in class names of the components.
</p>
<div class="card flex justify-center">

View File

@ -1,7 +1,7 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
The design tokens of a specific component is defined at <i>components</i> layer. Overriding components tokens is not the recommended approach if you are building our own style, building your own preset should be preferred instead. This
The design tokens of a specific component is defined at <i>components</i> layer. Overriding components tokens is not the recommended approach if you are building your own style, building your own preset should be preferred instead. This
configuration is global and applies to all card components, in case you need to customize a particular component on a page locally, view the Scoped CSS section for an example.
</p>
</DocSectionText>

View File

@ -2,7 +2,7 @@
<DocSectionText v-bind="$attrs">
<p>Selection of multiple nodes via checkboxes is enabled by configuring <i>selectionMode</i> as <i>checkbox</i>.</p>
<p>
In checkbox selection mode, value binding should be a key-value pair where key is the node key and value is an object that has <i>checked</i> and <i>partialChecked</i> properties to represent the checked state of a node obje to indicate
In checkbox selection mode, value binding should be a key-value pair where key is the node key and value is an object that has <i>checked</i> and <i>partialChecked</i> properties to represent the checked state of a node object to indicate
selection.
</p>
</DocSectionText>

View File

@ -2,7 +2,7 @@
<DocSectionText v-bind="$attrs">
<p>Selection of multiple nodes via checkboxes is enabled by configuring <i>selectionMode</i> as <i>checkbox</i>.</p>
<p>
In checkbox selection mode, value binding should be a key-value pair where key is the node key and value is an object that has <i>checked</i> and <i>partialChecked</i> properties to represent the checked state of a node obje to indicate
In checkbox selection mode, value binding should be a key-value pair where key is the node key and value is an object that has <i>checked</i> and <i>partialChecked</i> properties to represent the checked state of a node object to indicate
selection.
</p>
</DocSectionText>

View File

@ -0,0 +1,8 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Watch the short video tutorial from Çağatay Çivici to setup PrimeVue in styled mode with <a alt="Create Vue App" href="https://github.com/vuejs/create-vue">Create-Vue</a>.</p>
</DocSectionText>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/xW8EFqalm4I" frameborder="0" allowfullscreen></iframe>
</div>
</template>

View File

@ -1,11 +0,0 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
<a alt="Create Vue App" href="https://github.com/vuejs/create-vue">Create-Vue</a>
is the recommended way to start a Vite-powered Vue project.
</p>
</DocSectionText>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/FjYesOz95MM" frameborder="0" allowfullscreen></iframe>
</div>
</template>

View File

@ -1,6 +1,6 @@
{
"name": "showcase",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"description": "",
"homepage": "https://primevue.org/",

View File

@ -7,7 +7,7 @@
<div class="doc-main">
<div class="doc-intro">
<h1>Configuration</h1>
<p>Application widge configuration for PrimeVue.</p>
<p>Application widget configuration for PrimeVue.</p>
</div>
<DocSections :docs="docs" />
</div>

View File

@ -46,7 +46,7 @@ export default {
},
{
id: 'checkbox',
label: 'Check & Radio',
label: 'Checkbox & Radio',
component: CheckboxDoc
},
{

View File

@ -16,6 +16,7 @@ import BasicDoc from '@/doc/popover/BasicDoc.vue';
import DataTableDoc from '@/doc/popover/DataTableDoc.vue';
import ImportDoc from '@/doc/popover/ImportDoc.vue';
import PTComponent from '@/doc/popover/pt/index.vue';
import SelectDataDoc from '@/doc/popover/SelectDataDoc.vue';
import ThemingDoc from '@/doc/popover/theming/index.vue';
export default {
@ -32,6 +33,11 @@ export default {
label: 'Basic',
component: BasicDoc
},
{
id: 'selectdata',
label: 'Select Data',
component: SelectDataDoc
},
{
id: 'datatable',
label: 'DataTable',

View File

@ -1,5 +1,13 @@
<template>
<DocComponent title="Vue ProgressSpinner Component" header="ProgressSpinner" description="ProgressBar is a process status indicator." :componentDocs="docs" :apiDocs="['ProgressSpinner']" :ptTabComponent="ptComponent" :themingDocs="themingDoc" />
<DocComponent
title="Vue ProgressSpinner Component"
header="ProgressSpinner"
description="ProgressSpinner is a process status indicator."
:componentDocs="docs"
:apiDocs="['ProgressSpinner']"
:ptTabComponent="ptComponent"
:themingDocs="themingDoc"
/>
</template>
<script>

View File

@ -67,15 +67,24 @@
</div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">New Components</h2>
<p class="mt-0 mb-4 leading-normal">Layout, Typography, Tab orientations, Navigation Drawer.</p>
<h2 class="text-lg font-bold mt-0 mb-2">Form Library</h2>
<p class="mt-0 mb-4 leading-normal">Built-in form library with validations.</p>
<div class="bg-surface-200 rounded">
<div class="bg-blue-500 rounded" style="width: 25%; height: 4px"></div>
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">Components</h2>
<p class="mt-0 mb-4 leading-normal">New Carousel, Tab Orientations, Updated Menu, Navigation Drawer...</p>
<div class="bg-surface-200 rounded">
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
</div>
</div>
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">Form Library</h2>
<p class="mt-0 mb-4 leading-normal">Built-in form library with validations.</p>
<h2 class="text-lg font-bold mt-0 mb-2">Tailwind CSS Presets</h2>
<p class="mt-0 mb-4 leading-normal">Simplified usage in unstyled mode, typescript support, install via npx.</p>
<div class="bg-surface-200 rounded">
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
</div>
@ -94,11 +103,9 @@
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">Advanced Suite ... 2025</h2>
<p class="mt-0 mb-4 leading-normal">Gantt Chart, Flow Chart, Sheet, Calendar, Timeline, Editor.</p>
<h2 class="text-lg font-bold mt-0 mb-2">PrimeVue+ Suite | 2025</h2>
<p class="mt-0 mb-4 leading-normal">Gantt Chart, Flow Chart, Sheet, PDF Viewer, Calendar, Timeline, Editor.</p>
<div class="bg-surface-200 rounded">
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
</div>
@ -113,7 +120,7 @@
<h2 class="text-lg font-bold mt-0 mb-2">New Figma Tokens - Phase 1</h2>
<p class="mt-0 mb-4 leading-normal">Update tokens to sync with the new styled mode.</p>
<div class="bg-surface-200 rounded">
<div class="bg-indigo-500 rounded" style="width: 50%; height: 4px"></div>
<div class="bg-indigo-500 rounded" style="width: 100%; height: 4px"></div>
</div>
</div>
</div>
@ -122,9 +129,11 @@
<h2 class="text-lg font-bold mt-0 mb-2">New Figma Tokens - Phase 2</h2>
<p class="mt-0 mb-4 leading-normal">Update tokens to sync with the new styled mode.</p>
<div class="bg-surface-200 rounded">
<div class="bg-indigo-500 rounded" style="width: 0%; height: 4px"></div>
<div class="bg-indigo-500 rounded" style="width: 50%; height: 4px"></div>
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-indigo-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">Figma to Theme API</h2>
<p class="mt-0 mb-4 leading-normal">Build a Figma plugin to generate themes from UI Kit.</p>
@ -133,7 +142,6 @@
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col"></div>
</div>
<div class="flex gap-4 border-b border-surface-200 dark:border-surface-700 pb-4">
<div class="shrink-0 p-4 bg-teal-500 text-white rounded font-bold text-lg flex items-center justify-center w-56">SHOWCASE</div>
@ -144,7 +152,7 @@
<h2 class="text-lg font-bold mt-0 mb-2">Documentation</h2>
<p class="mt-0 mb-4 leading-normal">Interactive component viewer to explore tokens and pt sections.</p>
<div class="bg-surface-200 rounded">
<div class="bg-teal-500 rounded" style="width: 0%; height: 4px"></div>
<div class="bg-teal-500 rounded" style="width: 25%; height: 4px"></div>
</div>
</div>
</div>
@ -159,37 +167,37 @@
<h2 class="text-lg font-bold mt-0 mb-2">V4 Update</h2>
<p class="mt-0 mb-4 leading-normal">Update all templates to PrimeVue v4, replace PrimeFlex demos with Tailwind.</p>
<div class="bg-surface-200 rounded">
<div class="bg-teal-500 rounded" style="width: 0%; height: 4px"></div>
<div class="bg-violet-500 rounded" style="width: 100%; height: 4px"></div>
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-violet-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">Genesis</h2>
<p class="mt-0 mb-4 leading-normal">Brand new template application.</p>
<p class="mt-0 mb-4 leading-normal">Brand new multi-purpose template.</p>
<div class="bg-surface-200 rounded">
<div class="bg-teal-500 rounded" style="width: 0%; height: 4px"></div>
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col"></div>
</div>
<div class="flex gap-4 border-b border-surface-200 dark:border-surface-700 pb-4">
<div class="shrink-0 p-4 bg-orange-500 text-white rounded font-bold text-lg flex items-center justify-center w-56">PrimeBlocks</div>
<div class="flex-1 flex gap-4 flex-col"></div>
<div class="flex-1 flex gap-4 flex-col"></div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-orange-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">Tailwind Blocks</h2>
<p class="mt-0 mb-4 leading-normal">Migrate Blocks to Tailwind CSS.</p>
<p class="mt-0 mb-4 leading-normal">Migrate Blocks to v4 and Tailwind CSS.</p>
<div class="bg-surface-200 rounded">
<div class="bg-orange-500 rounded" style="width: 50%; height: 4px"></div>
<div class="bg-orange-500 rounded" style="width: 90%; height: 4px"></div>
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-orange-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">Online App</h2>
<p class="mt-0 mb-4 leading-normal">Implement a SaaS app to access the blocks instead of an offline download.</p>
<p class="mt-0 mb-4 leading-normal">Implement an app to access the blocks instead of an offline download.</p>
<div class="bg-surface-200 rounded">
<div class="bg-orange-500 rounded" style="width: 0%; height: 4px"></div>
<div class="bg-orange-500 rounded" style="width: 90%; height: 4px"></div>
</div>
</div>
</div>
@ -199,7 +207,7 @@
<div class="shrink-0 p-4 bg-pink-500 text-white rounded font-bold text-lg flex items-center justify-center w-56">Design</div>
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-pink-500 border-l-8">
<h2 class="text-lg font-bold mt-0 mb-2">New UI Theme</h2>
<h2 class="text-lg font-bold mt-0 mb-2">New Aura Theme</h2>
<p class="mt-0 mb-4 leading-normal">Brand new default theme with a modern and attractive design.</p>
<div class="bg-surface-200 rounded">
<div class="bg-pink-500 rounded" style="width: 100%; height: 4px"></div>
@ -207,6 +215,7 @@
</div>
</div>
<div class="flex-1 flex gap-4 flex-col"></div>
<div class="flex-1 flex gap-4 flex-col"></div>
<div class="flex-1 flex gap-4 flex-col">
<div class="flex-1 flex gap-4 flex-col">
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-pink-500 border-l-8">
@ -218,7 +227,6 @@
</div>
</div>
</div>
<div class="flex-1 flex gap-4 flex-col"></div>
</div>
</div>
</div>

View File

@ -43,18 +43,18 @@ export default {
license: {
documentLink: 'https://apollo.primevue.org/documentation/',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$59',
discount: '',
discount: '$39',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$590',
discount: '',
discount: '$390',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]

View File

@ -42,18 +42,18 @@ export default {
license: {
documentLink: 'https://atlantis.primevue.org/documentation',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$59',
discount: '',
discount: '$39',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$590',
discount: '',
discount: '$390',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]
@ -74,7 +74,7 @@ export default {
{
id: 2,
title: 'Component Themes',
description: 'Atlantis offers 16 built-in component themes with dark and light options. You are also free to create you own theme by defining couple SASS variables.',
description: 'Atlantis offers 16 built-in component themes with dark and light options. You are also free to create your own theme by defining couple SASS variables.',
src: 'https://primefaces.org/cdn/primevue/images/templates/atlantis/features-animation-component-themes.png'
},
{

View File

@ -44,18 +44,18 @@ export default {
license: {
documentLink: 'https://avalon.primevue.org/documentation',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$49',
discount: '',
discount: '$29',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$490',
discount: '',
discount: '$290',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]

View File

@ -43,18 +43,18 @@ export default {
license: {
documentLink: 'https://diamond.primevue.org/documentation/',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$59',
discount: '',
discount: '$39',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$590',
discount: '',
discount: '$390',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]

View File

@ -43,18 +43,18 @@ export default {
license: {
documentLink: 'https://freya.primevue.org/documentation',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$59',
discount: '',
discount: '$39',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$590',
discount: '',
discount: '$390',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]

View File

@ -43,18 +43,18 @@ export default {
license: {
documentLink: 'https://poseidon.primevue.org/documentation/',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$59',
discount: '',
discount: '$39',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$590',
discount: '',
discount: '$390',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]

View File

@ -44,18 +44,18 @@ export default {
license: {
documentLink: 'https://ultima.primevue.org/documentation/',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$59',
discount: '',
discount: '$39',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$590',
discount: '',
discount: '$390',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]

View File

@ -43,18 +43,18 @@ export default {
license: {
documentLink: 'https://verona.primevue.org/documentation',
description: 'The download package is a Vite-based project containing all application source codes deployed at the live demo. The project code is written in JavaScript.',
showDiscount: false,
showDiscount: true,
licenseDetails: [
{
title: 'Basic License',
price: '$49',
discount: '',
discount: '$29',
included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', '1 Year Free Updates']
},
{
title: 'Extended License',
price: '$490',
discount: '',
discount: '$290',
included: ['Commercial Usage', 'Multiple End Products', '1 Year Free Updates']
}
]
@ -75,7 +75,7 @@ export default {
{
id: 2,
title: 'Component Themes',
description: 'Verona offers 10 built-in component themes with dark and light options. You are also free to create you own theme by defining couple SASS variables.',
description: 'Verona offers 10 built-in component themes with dark and light options. You are also free to create your own theme by defining couple SASS variables.',
src: 'https://primefaces.org/cdn/primevue/images/templates/verona/features-animation-component-themes.png'
},
{

View File

@ -159,7 +159,8 @@
<div class="text-surface-500 dark:text-surface-400 font-medium">For individual designers</div>
<hr class="my-4 mx-0 border-t border-0 border-surface-200 dark:border-surface-700" />
<div class="flex flex-wrap gap-4">
<span class="text-2xl font-bold">$99</span>
<span class="text-2xl text-muted-color line-through">$99</span>
<span class="text-2xl font-bold">$49</span>
</div>
<hr class="my-4 mx-0 border-t border-0 border-surface-200 dark:border-surface-700" />
<ul class="list-none p-0 m-0 grow text-lg">
@ -201,7 +202,8 @@
<div class="text-surface-500 dark:text-surface-400 font-medium">For small teams</div>
<hr class="my-4 mx-0 border-t border-0 border-surface-200 dark:border-surface-700" />
<div class="flex flex-wrap gap-4">
<span class="text-2xl font-bold">$249</span>
<span class="text-2xl text-muted-color line-through">$249</span>
<span class="text-2xl font-bold">$149</span>
</div>
<hr class="my-4 mx-0 border-t border-0 border-surface-200 dark:border-surface-700" />
<ul class="list-none p-0 m-0 grow text-lg">

View File

@ -21,6 +21,7 @@ import ExamplesDoc from '@/doc/vite/ExamplesDoc.vue';
import StyledModeDoc from '@/doc/vite/StyledModeDoc.vue';
import UnstyledModeDoc from '@/doc/vite/UnstyledModeDoc.vue';
import UsageDoc from '@/doc/vite/UsageDoc.vue';
import VideoDoc from '@/doc/vite/VideoDoc.vue';
export default {
data() {
@ -58,6 +59,11 @@ export default {
id: 'examples',
label: 'Examples',
component: ExamplesDoc
},
{
id: 'video',
label: 'Video',
component: VideoDoc
}
]
};

View File

@ -1,6 +1,6 @@
{
"name": "@primevue/monorepo",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"homepage": "https://primevue.org/",
"repository": {

View File

@ -1,6 +1,6 @@
{
"name": "@primevue/auto-import-resolver",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"description": "",
"homepage": "https://primevue.org/",

View File

@ -1,6 +1,6 @@
{
"name": "@primevue/core",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"description": "",
"homepage": "https://primevue.org/",

View File

@ -161,15 +161,7 @@ export declare function usePrimeVue(): {
declare const plugin: Plugin;
export default plugin;
declare module 'vue/types/vue' {
interface Vue {
$primevue: {
config: PrimeVueConfiguration;
};
}
}
declare module '@vue/runtime-core' {
declare module 'vue' {
interface ComponentCustomProperties {
$primevue: {
config: PrimeVueConfiguration;

View File

@ -1,6 +1,6 @@
{
"name": "@primevue/icons",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"description": "",
"homepage": "https://primevue.org/",

View File

@ -1,6 +1,6 @@
{
"name": "@primevue/metadata",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"description": "",
"homepage": "https://primevue.org/",

View File

@ -1,6 +1,6 @@
{
"name": "@primevue/nuxt-module",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"description": "Nuxt module for PrimeVue",
"homepage": "https://primevue.org/",
@ -80,7 +80,7 @@
"@types/node": "^18.17.17",
"@nuxt/devtools": "^0.8.5",
"@nuxt/eslint-config": "^0.2.0",
"@nuxt/module-builder": "^0.5.1",
"@nuxt/module-builder": "^0.8.3",
"@nuxt/schema": "^3.7.3",
"@nuxt/test-utils": "^3.7.3",
"changelogen": "^0.5.5",

View File

@ -1,6 +1,6 @@
{
"name": "primevue",
"version": "4.0.4",
"version": "4.0.6",
"author": "PrimeTek Informatics",
"description": "PrimeVue is an open source UI library for Vue featuring a rich set of 80+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock, which has 370+ ready to use UI blocks to build spectacular applications in no time.",
"homepage": "https://primevue.org/",

View File

@ -180,6 +180,17 @@ const DialogEvents = [
}
]
},
{
name: 'dragstart',
description: 'Fired when a dialog drag begins.',
arguments: [
{
name: 'event',
type: 'object',
description: 'Event Object'
}
]
},
{
name: 'dragend',
description: 'Fired when a dialog drag completes.',

View File

@ -118,7 +118,7 @@ export interface AccordionProps {
* Value of the active panel or an array of values in multiple mode.
* @defaultValue null
*/
value?: string | string[] | null | undefined;
value?: string | string[] | number | number[] | null | undefined;
/**
* When enabled, multiple tabs can be activated at the same time.
* @defaultValue false

View File

@ -7,7 +7,7 @@ export default {
extends: BaseComponent,
props: {
value: {
type: [String, Array],
type: [String, Number, Array],
default: undefined
},
multiple: {

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { VNode } from 'vue';
import type { Component, VNode } from 'vue';
export declare type AccordionContentPassThroughOptionType = AccordionContentPassThroughAttributes | ((options: AccordionContentPassThroughMethodOptions) => AccordionContentPassThroughAttributes | string) | string | null | undefined;
@ -80,7 +80,7 @@ export interface AccordionContentProps {
* Use to change the HTML tag of root element.
* @defaultValue DIV
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false

View File

@ -7,7 +7,7 @@ export default {
extends: BaseComponent,
props: {
as: {
type: String,
type: [String, Object],
default: 'DIV'
},
asChild: {

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { VNode } from 'vue';
import type { Component, VNode } from 'vue';
export declare type AccordionHeaderPassThroughOptionType = AccordionHeaderPassThroughAttributes | ((options: AccordionHeaderPassThroughMethodOptions) => AccordionHeaderPassThroughAttributes | string) | string | null | undefined;
@ -76,7 +76,7 @@ export interface AccordionHeaderProps {
* Use to change the HTML tag of root element.
* @defaultValue BUTTON
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false

View File

@ -7,7 +7,7 @@ export default {
extends: BaseComponent,
props: {
as: {
type: String,
type: [String, Object],
default: 'BUTTON'
},
asChild: {

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { VNode } from 'vue';
import type { Component, VNode } from 'vue';
export declare type AccordionPanelPassThroughOptionType = AccordionPanelPassThroughAttributes | ((options: AccordionPanelPassThroughMethodOptions) => AccordionPanelPassThroughAttributes | string) | string | null | undefined;
@ -71,7 +71,7 @@ export interface AccordionPanelProps {
/**
* Unique value of item.
*/
value: string;
value: string | number | undefined;
/**
* Whether the item is disabled.
* @defaultValue false
@ -81,7 +81,7 @@ export interface AccordionPanelProps {
* Use to change the HTML tag of root element.
* @defaultValue DIV
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false

View File

@ -7,7 +7,7 @@ export default {
extends: BaseComponent,
props: {
value: {
type: String,
type: [String, Number],
default: undefined
},
disabled: {
@ -15,7 +15,7 @@ export default {
default: false
},
as: {
type: String,
type: [String, Object],
default: 'DIV'
},
asChild: {

View File

@ -43,7 +43,7 @@ export default {
default: undefined
},
as: {
type: String,
type: [String, Object],
default: 'BUTTON'
},
asChild: {

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, HintedString, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { ButtonHTMLAttributes, VNode } from 'vue';
import type { ButtonHTMLAttributes, Component, VNode } from 'vue';
export declare type ButtonPassThroughOptionType<T = any> = ButtonPassThroughAttributes | ((options: ButtonPassThroughMethodOptions<T>) => ButtonPassThroughAttributes | string) | string | null | undefined;
@ -133,7 +133,7 @@ export interface ButtonProps extends ButtonHTMLAttributes {
* Use to change the HTML tag of root element.
* @defaultValue BUTTON
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false

View File

@ -209,6 +209,25 @@ export interface CarouselContext {
* @defaultValue false
*/
highlighted: boolean;
/**
* Index of the item as a number.
*/
index: number;
/**
* Current active state of the item as a boolean.
* @defaultValue false
*/
active: boolean;
/**
* Current start state of the item as a boolean.
* @defaultValue false
*/
start: boolean;
/**
* Current end state of the item as a boolean.
* @defaultValue false
*/
end: boolean;
}
export interface CarouselResponsiveOptions {

View File

@ -45,7 +45,7 @@
:aria-hidden="firstIndex() > index || lastIndex() < index ? true : undefined"
:aria-label="ariaSlideNumber(index)"
:aria-roledescription="ariaSlideLabel"
v-bind="ptm('item')"
v-bind="getItemPTOptions('item', index)"
:data-p-carousel-item-active="firstIndex() <= index && lastIndex() >= index"
:data-p-carousel-item-start="firstIndex() === index"
:data-p-carousel-item-end="lastIndex() === index"
@ -78,7 +78,7 @@
</Button>
</div>
<ul v-if="totalIndicators >= 0 && showIndicators" ref="indicatorContent" :class="[cx('indicatorList'), indicatorsContentClass]" @keydown="onIndicatorKeydown" v-bind="ptm('indicatorList')">
<li v-for="(indicator, i) of totalIndicators" :key="'p-carousel-indicator-' + i.toString()" :class="cx('indicator', { index: i })" v-bind="ptm('indicator', getIndicatorPTOptions(i))" :data-p-active="d_page === i">
<li v-for="(indicator, i) of totalIndicators" :key="'p-carousel-indicator-' + i.toString()" :class="cx('indicator', { index: i })" v-bind="getIndicatorPTOptions('indicator', i)" :data-p-active="d_page === i">
<button
:class="cx('indicatorButton')"
type="button"
@ -86,7 +86,7 @@
:aria-label="ariaPageLabel(i + 1)"
:aria-current="d_page === i ? 'page' : undefined"
@click="onIndicatorClick($event, i)"
v-bind="ptm('indicatorButton', getIndicatorPTOptions(i))"
v-bind="getIndicatorPTOptions('indicatorButton', i)"
/>
</li>
</ul>
@ -101,9 +101,9 @@
</template>
<script>
import { UniqueComponentId } from '@primevue/core/utils';
import { removeClass, addClass, find, findSingle, getAttribute, setAttribute } from '@primeuix/utils/dom';
import { addClass, find, findSingle, getAttribute, removeClass, setAttribute } from '@primeuix/utils/dom';
import { localeComparator, sort } from '@primeuix/utils/object';
import { UniqueComponentId } from '@primevue/core/utils';
import ChevronDownIcon from '@primevue/icons/chevrondown';
import ChevronLeftIcon from '@primevue/icons/chevronleft';
import ChevronRightIcon from '@primevue/icons/chevronright';
@ -272,12 +272,22 @@ export default {
}
},
methods: {
getIndicatorPTOptions(index) {
return {
getIndicatorPTOptions(key, index) {
return this.ptm(key, {
context: {
highlighted: index === this.d_page
}
};
});
},
getItemPTOptions(key, index) {
return this.ptm(key, {
context: {
index,
active: this.firstIndex() <= index && this.lastIndex() >= index,
start: this.firstIndex() === index,
end: this.lastIndex() === index
}
});
},
step(dir, page) {
let totalShiftedItems = this.totalShiftedItems;

View File

@ -105,7 +105,7 @@ export interface ChartProps {
/**
* Used to custom plugins of the chart.
*/
plugins?: any;
plugins?: any[];
/**
* Width of the chart in non-responsive mode.
* @defaultValue 300

View File

@ -45,6 +45,7 @@ import type { FloatLabelPassThroughOptions } from 'primevue/floatlabel';
import type { FluidPassThroughOptions } from 'primevue/fluid';
import type { FocusTrapDirectivePassThroughOptions } from 'primevue/focustrap';
import type { GalleriaPassThroughOptions } from 'primevue/galleria';
import type { IconFieldPassThroughOptions } from 'primevue/iconfield';
import type { ImagePassThroughOptions } from 'primevue/image';
import type { InlineMessagePassThroughOptions } from 'primevue/inlinemessage';
import type { InplacePassThroughOptions } from 'primevue/inplace';
@ -199,6 +200,7 @@ export interface PrimeVuePTOptions {
floatlabel?: DefaultPassThrough<FloatLabelPassThroughOptions>;
fluid?: DefaultPassThrough<FluidPassThroughOptions>;
galleria?: DefaultPassThrough<GalleriaPassThroughOptions>;
iconfield?: DefaultPassThrough<IconFieldPassThroughOptions>;
image?: DefaultPassThrough<ImagePassThroughOptions>;
inlinemessage?: DefaultPassThrough<InlineMessagePassThroughOptions>;
inplace?: DefaultPassThrough<InplacePassThroughOptions>;

View File

@ -27,13 +27,7 @@ export interface ConfirmationServiceMethods {
close(): void;
}
declare module 'vue/types/vue' {
interface Vue {
$confirm: ConfirmationServiceMethods;
}
}
declare module '@vue/runtime-core' {
declare module 'vue' {
interface ComponentCustomProperties {
$confirm: ConfirmationServiceMethods;
}

View File

@ -28,7 +28,7 @@
v-bind="getPTOptions('itemContent', processedItem, index)"
>
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions('itemLink', processedItem, index)">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" v-bind="getPTOptions('itemLink', processedItem, index)">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="cx('itemIcon')" />
<span v-else-if="getItemProp(processedItem, 'icon')" :class="[cx('itemIcon'), getItemProp(processedItem, 'icon')]" v-bind="getPTOptions('itemIcon', processedItem, index)" />
<span :id="getItemLabelId(processedItem)" :class="cx('itemLabel')" v-bind="getPTOptions('itemLabel', processedItem, index)">{{ getItemLabel(processedItem) }}</span>
@ -75,9 +75,9 @@
</template>
<script>
import BaseComponent from '@primevue/core/basecomponent';
import { nestedPosition } from '@primeuix/utils/dom';
import { resolve, isNotEmpty } from '@primeuix/utils/object';
import { isNotEmpty, resolve } from '@primeuix/utils/object';
import BaseComponent from '@primevue/core/basecomponent';
import AngleRightIcon from '@primevue/icons/angleright';
import Ripple from 'primevue/ripple';
import { mergeProps } from 'vue';
@ -144,7 +144,7 @@ export default {
getPTOptions(key, processedItem, index) {
return this.ptm(key, {
context: {
item: processedItem,
item: processedItem.item,
active: this.isItemActive(processedItem),
focused: this.isItemFocused(processedItem),
disabled: this.isItemDisabled(processedItem),

View File

@ -621,7 +621,7 @@ export interface DataTableStateEvent {
/**
* Comma separated list of column widths
*/
columWidths: string[];
columnWidths: string[];
/**
* Order of the columns
*/

View File

@ -458,7 +458,7 @@ describe('DataTable.vue', () => {
await wrapper.setProps({ selection: null, selectionMode: 'single' });
await wrapper.vm.onRowClick({
originalEvent: { target: wrapper.findAll('tr.p-datatable-selectable-row')[0].element },
originalEvent: { currentTarget: wrapper.findAll('tr.p-datatable-selectable-row')[0].element },
data: smallData[0],
index: 0
});
@ -472,13 +472,13 @@ describe('DataTable.vue', () => {
await wrapper.setProps({ selection: null, selectionMode: 'multiple' });
await wrapper.vm.onRowClick({
originalEvent: { shiftKey: true, target: wrapper.findAll('tr.p-datatable-selectable-row')[0].element },
originalEvent: { shiftKey: true, currentTarget: wrapper.findAll('tr.p-datatable-selectable-row')[0].element },
data: smallData[0],
index: 0
});
await wrapper.vm.onRowClick({
originalEvent: { shiftKey: true, target: wrapper.findAll('tr.p-datatable-selectable-row')[1].element },
originalEvent: { shiftKey: true, currentTarget: wrapper.findAll('tr.p-datatable-selectable-row')[1].element },
data: smallData[1],
index: 1
});
@ -492,13 +492,13 @@ describe('DataTable.vue', () => {
await wrapper.setProps({ selection: null, selectionMode: 'multiple', metaKeySelection: false });
await wrapper.vm.onRowClick({
originalEvent: { target: wrapper.findAll('.p-datatable-selectable-row')[0].element },
originalEvent: { currentTarget: wrapper.findAll('.p-datatable-selectable-row')[0].element },
data: smallData[0],
index: 0
});
await wrapper.vm.onRowClick({
originalEvent: { target: wrapper.findAll('tr.p-datatable-selectable-row')[1].element },
originalEvent: { currentTarget: wrapper.findAll('tr.p-datatable-selectable-row')[1].element },
data: smallData[1],
index: 1
});

View File

@ -280,29 +280,29 @@
</template>
<script>
import { FilterMatchMode, FilterOperator, FilterService } from '@primevue/core/api';
import { HelperSet, UniqueComponentId, getVNodeProp } from '@primevue/core/utils';
import {
getAttribute,
clearSelection,
findSingle,
isClickable,
find,
focus,
exportCSV,
getOffset,
addStyle,
getIndex,
getOuterWidth,
getHiddenElementOuterWidth,
getHiddenElementOuterHeight,
getWindowScrollTop,
getOuterHeight,
removeClass,
addClass,
addStyle,
clearSelection,
exportCSV,
find,
findSingle,
focus,
getAttribute,
getHiddenElementOuterHeight,
getHiddenElementOuterWidth,
getIndex,
getOffset,
getOuterHeight,
getOuterWidth,
getWindowScrollTop,
isClickable,
removeClass,
setAttribute
} from '@primeuix/utils/dom';
import { resolveFieldData, localeComparator, sort, findIndexInList, equals, reorderArray, isNotEmpty, isEmpty } from '@primeuix/utils/object';
import { equals, findIndexInList, isEmpty, isNotEmpty, localeComparator, reorderArray, resolveFieldData, sort } from '@primeuix/utils/object';
import { FilterMatchMode, FilterOperator, FilterService } from '@primevue/core/api';
import { HelperSet, UniqueComponentId, getVNodeProp } from '@primevue/core/utils';
import ArrowDownIcon from '@primevue/icons/arrowdown';
import ArrowUpIcon from '@primevue/icons/arrowup';
import SpinnerIcon from '@primevue/icons/spinner';
@ -736,7 +736,7 @@ export default {
const body = this.$refs.bodyRef && this.$refs.bodyRef.$el;
const focusedItem = findSingle(body, 'tr[data-p-selectable-row="true"][tabindex="0"]');
if (isClickable(event.target)) {
if (isClickable(event.currentTarget)) {
return;
}
@ -813,9 +813,9 @@ export default {
this.rowTouched = false;
if (focusedItem) {
if (event.target?.getAttribute('data-pc-section') === 'rowtoggleicon' || event.target?.parentElement?.getAttribute('data-pc-section') === 'rowtoggleicon') return;
if (event.currentTarget?.getAttribute('data-pc-section') === 'rowtoggleicon') return;
const targetRow = event.target?.closest('tr[data-p-selectable-row="true"]');
const targetRow = event.currentTarget?.closest('tr[data-p-selectable-row="true"]');
focusedItem.tabIndex = '-1';
targetRow.tabIndex = '0';

View File

@ -54,4 +54,48 @@ describe('DatePicker.vue', () => {
expect(wrapper.vm.viewDate).toEqual(dateTwo);
});
it('should open a year view when there is selected date (fix: #6203)', async () => {
const dateOne = new Date();
dateOne.setFullYear(1988, 9, 10);
await wrapper.setProps({ modelValue: dateOne });
const input = wrapper.find('.p-datepicker-input');
await input.trigger('focus');
const yearSelectButton = wrapper.find('.p-datepicker .p-datepicker-select-year');
expect(yearSelectButton.exists()).toBe(true);
expect(yearSelectButton.text()).toBe('1988');
await yearSelectButton.trigger('click');
expect(wrapper.find('.p-datepicker-decade').exists()).toBe(true);
expect(wrapper.find('.p-datepicker-decade').text()).toBe('1980 - 1989');
});
it('should not show other months when showOtherMonths is false', async () => {
const dateOne = new Date();
dateOne.setFullYear(1988, 5, 15);
await wrapper.setProps({ modelValue: dateOne, showOtherMonths: false });
const input = wrapper.find('.p-datepicker-input');
await input.trigger('focus');
expect(wrapper.find('.p-datepicker-other-month span').exists()).toBe(false);
await input.trigger('blur');
await wrapper.setProps({ showOtherMonths: true });
await input.trigger('focus');
expect(wrapper.find('.p-datepicker-other-month span').exists()).toBe(true);
});
});

View File

@ -78,7 +78,7 @@
<div :class="cx('header')" v-bind="ptm('header')">
<slot name="header"></slot>
<Button
v-show="showOtherMonths ? groupIndex === 0 : false"
v-show="groupIndex === 0"
:ref="previousButtonRef"
:class="cx('pcPrevButton')"
:disabled="disabled"
@ -158,7 +158,7 @@
</span>
</div>
<Button
v-show="showOtherMonths ? (numberOfMonths === 1 ? true : groupIndex === numberOfMonths - 1) : false"
v-show="numberOfMonths === 1 ? true : groupIndex === numberOfMonths - 1"
:ref="nextButtonRef"
:class="cx('pcNextButton')"
:disabled="disabled"
@ -223,6 +223,7 @@
data-pc-group-section="tablebodycell"
>
<span
v-if="showOtherMonths || !date.otherMonth"
v-ripple
:class="cx('day', { date })"
@click="onDateSelect($event, date)"
@ -750,7 +751,7 @@ export default {
return start === year || end === year || (start < year && end > year);
} else {
return value.getFullYear() === year;
return this.modelValue.getFullYear() === year;
}
},
isDateEquals(value, dateMeta) {
@ -906,16 +907,12 @@ export default {
this.overlay = null;
},
onPrevButtonClick(event) {
if (this.showOtherMonths) {
this.navigationState = { backward: true, button: true };
this.navBackward(event);
}
this.navigationState = { backward: true, button: true };
this.navBackward(event);
},
onNextButtonClick(event) {
if (this.showOtherMonths) {
this.navigationState = { backward: false, button: true };
this.navForward(event);
}
this.navigationState = { backward: false, button: true };
this.navForward(event);
},
navBackward(event) {
event.preventDefault();
@ -2710,14 +2707,14 @@ export default {
for (let i = 0; i < responsiveOptions.length; i++) {
let { breakpoint, numMonths } = responsiveOptions[i];
let styles = `
.p-datepicker[${this.attributeSelector}] .p-datepicker-group:nth-child(${numMonths}) .p-datepicker-next {
.p-datepicker-panel[${this.attributeSelector}] .p-datepicker-calendar:nth-child(${numMonths}) .p-datepicker-next-button {
display: inline-flex;
}
`;
for (let j = numMonths; j < this.numberOfMonths; j++) {
styles += `
.p-datepicker[${this.attributeSelector}] .p-datepicker-group:nth-child(${j + 1}) {
.p-datepicker-panel[${this.attributeSelector}] .p-datepicker-calendar:nth-child(${j + 1}) {
display: none;
}
`;

View File

@ -401,6 +401,11 @@ export interface DialogEmitsOptions {
* @param {event} event - Browser event.
*/
unmaximize(event: Event): void;
/**
* Fired when a dialog drag begins.
* @param {event} event - Browser event.
*/
dragstart(event: Event): void;
/**
* Fired when a dialog drag completes.
* @param {event} event - Browser event.

View File

@ -1,7 +1,7 @@
<template>
<Portal :appendTo="appendTo">
<div v-if="containerVisible" :ref="maskRef" :class="cx('mask')" :style="sx('mask', true, { position, modal })" @mousedown="onMaskMouseDown" @mouseup="onMaskMouseUp" v-bind="ptm('mask')">
<transition name="p-dialog" @before-enter="onBeforeEnter" @enter="onEnter" @before-leave="onBeforeLeave" @leave="onLeave" @after-leave="onAfterLeave" appear v-bind="ptm('transition')">
<transition name="p-dialog" @before-enter="onBeforeEnter" @enter="onEnter" @after-enter="onAfterEnter" @before-leave="onBeforeLeave" @leave="onLeave" @after-leave="onAfterLeave" appear v-bind="ptm('transition')">
<div v-if="visible" :ref="containerRef" v-focustrap="{ disabled: !modal }" :class="cx('root')" :style="sx('root')" role="dialog" :aria-labelledby="ariaLabelledById" :aria-modal="modal" v-bind="ptmi('root')">
<slot v-if="$slots.container" name="container" :closeCallback="close" :maximizeCallback="(event) => maximize(event)"></slot>
<template v-else>
@ -79,7 +79,7 @@ export default {
name: 'Dialog',
extends: BaseDialog,
inheritAttrs: false,
emits: ['update:visible', 'show', 'hide', 'after-hide', 'maximize', 'unmaximize', 'dragend'],
emits: ['update:visible', 'show', 'hide', 'after-hide', 'maximize', 'unmaximize', 'dragstart', 'dragend'],
provide() {
return {
dialogRef: computed(() => this._instance)
@ -149,7 +149,6 @@ export default {
onEnter() {
this.$emit('show');
this.target = document.activeElement;
this.focus();
this.enableDocumentSettings();
this.bindGlobalListeners();
@ -157,10 +156,17 @@ export default {
ZIndex.set('modal', this.mask, this.baseZIndex + this.$primevue.config.zIndex.modal);
}
},
onAfterEnter() {
this.focus();
},
onBeforeLeave() {
if (this.modal) {
!this.isUnstyled && addClass(this.mask, 'p-overlay-mask-leave');
}
if (this.dragging && this.documentDragEndListener) {
this.documentDragEndListener();
}
},
onLeave() {
this.$emit('hide');
@ -318,6 +324,8 @@ export default {
this.container.style.margin = '0';
document.body.setAttribute('data-p-unselectable-text', 'true');
!this.isUnstyled && addStyle(document.body, { 'user-select': 'none' });
this.$emit('dragstart', event);
}
},
bindGlobalListeners() {

View File

@ -26,13 +26,7 @@ export interface DialogServiceMethods {
open(content: any, options?: DynamicDialogOptions): DynamicDialogInstance;
}
declare module 'vue/types/vue' {
interface Vue {
$dialog: DialogServiceMethods;
}
}
declare module '@vue/runtime-core' {
declare module 'vue' {
interface ComponentCustomProperties {
$dialog: DialogServiceMethods;
}

View File

@ -59,15 +59,6 @@ export default {
$pcDrawer: this,
$parentInstance: this
};
},
watch: {
dismissable(newValue) {
if (newValue) {
this.bindOutsideClickListener();
} else {
this.unbindOutsideClickListener();
}
}
}
};
</script>

View File

@ -68,6 +68,15 @@ export default {
closeButton: null,
outsideClickListener: null,
documentKeydownListener: null,
watch: {
dismissable(newValue) {
if (newValue) {
this.bindOutsideClickListener();
} else {
this.unbindOutsideClickListener();
}
}
},
updated() {
if (this.visible) {
this.containerVisible = this.visible;

View File

@ -274,16 +274,6 @@ export interface FileUploadPassThroughOptions {
* Used to pass attributes to the empty's DOM element.
*/
empty?: FileUploadPassThroughOptionType;
/**
* Used to pass attributes to the messages' DOM element.
* @see {@link MessagePassThroughOptions}
*/
pcMessages?: MessagePassThroughOptions<FileUploadPassThroughMethodOptions>;
/**
* Used to pass attributes to the basic mode's button's DOM element.
* @see {@link ButtonPassThroughOptions}
*/
pcButton?: ButtonPassThroughOptions<FileUploadPassThroughMethodOptions>;
/**
* Used to manage all lifecycle hooks.
* @see {@link BaseComponent.ComponentHooks}
@ -314,7 +304,7 @@ export interface FileUploadState {
/**
* Current messages.
*/
messages: any[];
messages: string[] | null;
/**
* Current progress state as a number.
*/

View File

@ -55,14 +55,23 @@
</div>
</div>
<div v-else-if="isBasic" :class="cx('root')" v-bind="ptmi('root')">
<Message v-for="msg of messages" :key="msg" severity="error" @close="onMessageClose" :unstyled="unstyled" :pt="ptm('pcMessages')">{{ msg }}</Message>
<Button :label="chooseButtonLabel" :class="chooseButtonClass" :style="style" :disabled="disabled" :unstyled="unstyled" @mouseup="onBasicUploaderClick" @keydown.enter="choose" @focus="onFocus" @blur="onBlur" v-bind="ptm('pcButton')">
<Message v-for="msg of messages" :key="msg" severity="error" @close="onMessageClose" :unstyled="unstyled" :pt="ptm('pcMessage')">{{ msg }}</Message>
<Button
:label="chooseButtonLabel"
:class="chooseButtonClass"
:style="style"
:disabled="disabled"
:unstyled="unstyled"
@mouseup="onBasicUploaderClick"
@keydown.enter="choose"
@focus="onFocus"
@blur="onBlur"
v-bind="chooseButtonProps"
:pt="ptm('pcChooseButton')"
>
<template #icon="iconProps">
<slot v-if="!hasFiles || auto" name="uploadicon">
<component :is="uploadIcon ? 'span' : 'UploadIcon'" :class="[iconProps.class, uploadIcon]" aria-hidden="true" v-bind="ptm('pcButton')['icon']" />
</slot>
<slot v-else name="chooseicon">
<component :is="chooseIcon ? 'span' : 'PlusIcon'" :class="[iconProps.class, chooseIcon]" aria-hidden="true" v-bind="ptm('pcButton')['icon']" />
<slot name="chooseicon">
<component :is="chooseIcon ? 'span' : 'PlusIcon'" :class="[iconProps.class, chooseIcon]" aria-hidden="true" v-bind="ptm('pcChooseButton')['icon']" />
</slot>
</template>
</Button>
@ -71,7 +80,7 @@
{{ basicFileChosenLabel }}
</span>
</slot>
<input v-if="!hasFiles" ref="fileInput" type="file" :accept="accept" :disabled="disabled" :multiple="multiple" @change="onFileSelect" @focus="onFocus" @blur="onBlur" v-bind="ptm('input')" />
<input ref="fileInput" type="file" :accept="accept" :disabled="disabled" :multiple="multiple" @change="onFileSelect" @focus="onFocus" @blur="onBlur" v-bind="ptm('input')" />
</div>
</template>
@ -108,7 +117,7 @@ export default {
if (this.hasFiles) this.uploader();
},
onBasicUploaderClick(event) {
if (event.button === 0 && !this.hasFiles) this.$refs.fileInput.click();
if (event.button === 0) this.$refs.fileInput.click();
},
onFileSelect(event) {
if (event.type !== 'drop' && this.isIE11() && this.duplicateIEEvent) {
@ -117,6 +126,10 @@ export default {
return;
}
if (this.isBasic && this.hasFiles) {
this.files = [];
}
this.messages = [];
this.files = this.files || [];
let files = event.dataTransfer ? event.dataTransfer.files : event.target.files;

View File

@ -2,7 +2,7 @@
*
* IconField wraps an input and an icon.
*
* [Live Demo](https://www.primevue.org/inputtext/)
* [Live Demo](https://www.primevue.org/iconfield/)
*
* @module iconfield
*
@ -110,7 +110,7 @@ export declare type IconFieldEmits = EmitFn<IconFieldEmitsOptions>;
*
* _IconField is used to select a boolean value._
*
* [Live Demo](https://www.primevue.org/inputtext/)
* [Live Demo](https://www.primevue.org/iconfield/)
* --- ---
* ![PrimeVue](https://primefaces.org/cdn/primevue/images/logo-100.png)
*

View File

@ -86,9 +86,9 @@ const theme = ({ dt }) => `
}
.p-image-action:focus-visible {
box-shadow: ${dt('toolbar.action.focus.ring.shadow')};
outline: ${dt('toolbar.action.focus.ring.width')} ${dt('toolbar.action.focus.ring.style')} ${dt('toolbar.action.focus.ring.color')};
outline-offset: ${dt('toolbar.action.focus.ring.offset')};
box-shadow: ${dt('image.action.focus.ring.shadow')};
outline: ${dt('image.action.focus.ring.width')} ${dt('image.action.focus.ring.style')} ${dt('image.action.focus.ring.color')};
outline-offset: ${dt('image.action.focus.ring.offset')};
}
.p-image-action .p-icon {

View File

@ -12,6 +12,7 @@
:fluid="hasFluid"
:unstyled="unstyled"
@input="onInput"
@compositionend="onInput"
@focus="onFocus"
@blur="onBlur"
@keydown="onKeyDown"
@ -53,10 +54,14 @@ export default {
},
methods: {
onInput(event) {
if (this.androidChrome) this.handleAndroidInput(event);
else this.handleInputChange(event);
// Check if the event is part of a text composition process (e.g., for Asian languages).
// If event.isComposing is true, it means the user is still composing text and the input is not finalized.
if (!event.isComposing) {
if (this.androidChrome) this.handleAndroidInput(event);
else this.handleInputChange(event);
this.$emit('update:modelValue', event.target.value);
this.$emit('update:modelValue', event.target.value);
}
},
onFocus(event) {
if (this.readonly) {

View File

@ -40,6 +40,7 @@ const theme = ({ dt }) => `
top: 1px;
right: 1px;
height: calc(100% - 2px);
z-index: 1;
}
.p-inputnumber-stacked .p-inputnumber-increment-button {

View File

@ -161,11 +161,12 @@ export default {
break;
case 'Enter':
case 'NumpadEnter':
case 'Tab':
break;
default:
if ((this.integerOnly && !(Number(event.key) >= 0 && Number(event.key) <= 9)) || (this.tokens.join('').length >= this.length && event.code !== 'Delete')) {
if ((this.integerOnly && !(event.code !== 'Space' && Number(event.key) >= 0 && Number(event.key) <= 9)) || (this.tokens.join('').length >= this.length && event.code !== 'Delete')) {
event.preventDefault();
}

View File

@ -33,7 +33,7 @@
@keydown="onFilterKeyDown"
:pt="ptm('pcFilter')"
/>
<InputIcon :unstyled="unstyled" v-bind="ptm('pcFilterIconContainer')">
<InputIcon :unstyled="unstyled" :pt="ptm('pcFilterIconContainer')">
<slot name="filtericon">
<span v-if="filterIcon" :class="filterIcon" v-bind="ptm('filterIcon')" />
<SearchIcon v-else v-bind="ptm('filterIcon')" />

View File

@ -22,7 +22,7 @@
>
<div :class="cx('itemContent')" @click="onItemClick($event, processedItem)" @mouseenter="onItemMouseEnter($event, processedItem)" v-bind="getPTOptions(processedItem, index, 'itemContent')">
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions(processedItem, index, 'itemLink')">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" v-bind="getPTOptions(processedItem, index, 'itemLink')">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="cx('itemIcon')" />
<span v-else-if="getItemProp(processedItem, 'icon')" :class="[cx('itemIcon'), getItemProp(processedItem, 'icon')]" v-bind="getPTOptions(processedItem, index, 'itemIcon')" />
<span :class="cx('itemLabel')" v-bind="getPTOptions(processedItem, index, 'itemLabel')">
@ -74,8 +74,8 @@
</template>
<script>
import { isNotEmpty, resolve } from '@primeuix/utils/object';
import BaseComponent from '@primevue/core/basecomponent';
import { resolve, isNotEmpty } from '@primeuix/utils/object';
import AngleDownIcon from '@primevue/icons/angledown';
import AngleRightIcon from '@primevue/icons/angleright';
import Ripple from 'primevue/ripple';
@ -150,7 +150,7 @@ export default {
getPTOptions(processedItem, index, key) {
return this.ptm(key, {
context: {
item: processedItem,
item: processedItem.item,
index,
active: this.isItemActive(processedItem),
focused: this.isItemFocused(processedItem),

View File

@ -13,7 +13,7 @@
>
<div :class="cx('itemContent')" @click="onItemClick($event)" @mousemove="onItemMouseMove($event)" v-bind="getPTOptions('itemContent')">
<template v-if="!templates.item">
<a v-ripple :href="item.url" :class="cx('itemLink')" :target="item.target" tabindex="-1" aria-hidden="true" v-bind="getPTOptions('itemLink')">
<a v-ripple :href="item.url" :class="cx('itemLink')" :target="item.target" tabindex="-1" v-bind="getPTOptions('itemLink')">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="item" :class="cx('itemIcon')" />
<span v-else-if="item.icon" :class="[cx('itemIcon'), item.icon]" v-bind="getPTOptions('itemIcon')" />
<span :class="cx('itemLabel')" v-bind="getPTOptions('itemLabel')">{{ label() }}</span>
@ -25,8 +25,8 @@
</template>
<script>
import BaseComponent from '@primevue/core/basecomponent';
import { resolve } from '@primeuix/utils/object';
import BaseComponent from '@primevue/core/basecomponent';
import Ripple from 'primevue/ripple';
import { mergeProps } from 'vue';

View File

@ -12,7 +12,7 @@
:aria-expanded="isItemGroup(processedItem) ? isItemActive(processedItem) : undefined"
:aria-haspopup="isItemGroup(processedItem) && !getItemProp(processedItem, 'to') ? 'menu' : undefined"
:aria-level="level + 1"
:aria-setsize="getAriaSetSize()"
:aria-setsize="getAriaSetSize"
:aria-posinset="getAriaPosInset(index)"
v-bind="getPTOptions(processedItem, index, 'item')"
:data-p-active="isItemActive(processedItem)"
@ -27,7 +27,7 @@
v-bind="getPTOptions(processedItem, index, 'itemContent')"
>
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions(processedItem, index, 'itemLink')">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" v-bind="getPTOptions(processedItem, index, 'itemLink')">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="cx('itemIcon')" />
<span v-else-if="getItemProp(processedItem, 'icon')" :class="[cx('itemIcon'), getItemProp(processedItem, 'icon')]" v-bind="getPTOptions(processedItem, index, 'itemIcon')" />
<span :id="getItemLabelId(processedItem)" :class="cx('itemLabel')" v-bind="getPTOptions(processedItem, index, 'itemLabel')">{{ getItemLabel(processedItem) }}</span>
@ -72,8 +72,8 @@
</template>
<script>
import { isNotEmpty, resolve } from '@primeuix/utils/object';
import BaseComponent from '@primevue/core/basecomponent';
import { resolve, isNotEmpty } from '@primeuix/utils/object';
import AngleDownIcon from '@primevue/icons/angledown';
import AngleRightIcon from '@primevue/icons/angleright';
import Ripple from 'primevue/ripple';
@ -123,6 +123,7 @@ export default {
}
},
list: null,
methods: {
getItemId(processedItem) {
return `${this.menuId}_${processedItem.key}`;
@ -142,7 +143,7 @@ export default {
getPTOptions(processedItem, index, key) {
return this.ptm(key, {
context: {
item: processedItem,
item: processedItem.item,
index,
active: this.isItemActive(processedItem),
focused: this.isItemFocused(processedItem),
@ -176,11 +177,8 @@ export default {
onItemMouseMove(event, processedItem) {
this.$emit('item-mousemove', { originalEvent: event, processedItem });
},
getAriaSetSize() {
return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length;
},
getAriaPosInset(index) {
return index - this.items.slice(0, index).filter((processedItem) => this.isItemVisible(processedItem) && this.getItemProp(processedItem, 'separator')).length + 1;
return index - this.calculateAriaSetSize.slice(0, index).length + 1;
},
getMenuItemProps(processedItem, index) {
return {
@ -213,6 +211,14 @@ export default {
};
}
},
computed: {
calculateAriaSetSize() {
return this.items.filter((processedItem) => this.isItemVisible(processedItem) && this.getItemProp(processedItem, 'separator'));
},
getAriaSetSize() {
return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length;
}
},
components: {
AngleRightIcon: AngleRightIcon,
AngleDownIcon: AngleDownIcon

View File

@ -106,7 +106,7 @@
@input="onFilterChange"
:pt="ptm('pcFilter')"
/>
<InputIcon :unstyled="unstyled" v-bind="ptm('pcFilterIconContainer')">
<InputIcon :unstyled="unstyled" :pt="ptm('pcFilterIconContainer')">
<slot name="filtericon">
<span v-if="filterIcon" :class="filterIcon" v-bind="ptm('filterIcon')" />
<SearchIcon v-else v-bind="ptm('filterIcon')" />

View File

@ -18,7 +18,7 @@
>
<div :class="cx('itemContent')" @click="onItemClick($event, processedItem)" @mousemove="onItemMouseMove($event, processedItem)" v-bind="getPTOptions('itemContent', processedItem, index)">
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions('itemLink', processedItem, index)">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('itemLink')" :target="getItemProp(processedItem, 'target')" tabindex="-1" v-bind="getPTOptions('itemLink', processedItem, index)">
<template v-if="isItemGroup(processedItem)">
<component v-if="templates.submenuicon" :is="templates.submenuicon" :class="cx('submenuIcon')" :active="isItemActive(processedItem)" v-bind="getPTOptions('submenuIcon', processedItem, index)" />
<component v-else :is="isItemActive(processedItem) ? 'ChevronDownIcon' : 'ChevronRightIcon'" :class="cx('submenuIcon')" v-bind="getPTOptions('submenuIcon', processedItem, index)" />
@ -72,8 +72,8 @@
</template>
<script>
import { isNotEmpty, resolve } from '@primeuix/utils/object';
import BaseComponent from '@primevue/core/basecomponent';
import { resolve, isNotEmpty } from '@primeuix/utils/object';
import ChevronDownIcon from '@primevue/icons/chevrondown';
import ChevronRightIcon from '@primevue/icons/chevronright';
import Ripple from 'primevue/ripple';
@ -130,7 +130,7 @@ export default {
getPTOptions(key, processedItem, index) {
return this.ptm(key, {
context: {
item: processedItem,
item: processedItem.item,
index,
active: this.isItemActive(processedItem),
focused: this.isItemFocused(processedItem),

View File

@ -2,13 +2,13 @@ import BaseStyle from '@primevue/core/base/style';
const theme = ({ dt }) => `
.p-scrolltop.p-button {
position: fixed;
position: fixed !important;
bottom: 20px;
right: 20px;
}
.p-scrolltop-sticky.p-button {
position: sticky;
position: sticky !important;
display: flex;
margin-left: auto;
}

View File

@ -96,7 +96,7 @@
@input="onFilterChange"
:pt="ptm('pcFilter')"
/>
<InputIcon :unstyled="unstyled" v-bind="ptm('pcFilterIconContainer')">
<InputIcon :unstyled="unstyled" :pt="ptm('pcFilterIconContainer')">
<slot name="filtericon">
<span v-if="filterIcon" :class="filterIcon" v-bind="ptm('filterIcon')" />
<SearchIcon v-else v-bind="ptm('filterIcon')" />
@ -495,6 +495,10 @@ export default {
!this.virtualScrollerDisabled && this.virtualScroller.scrollToIndex(0);
},
onFilterKeyDown(event) {
// Check if the event is part of a text composition process (e.g., for Asian languages).
// If event.isComposing is true, it means the user is still composing text and the input is not finalized.
if (event.isComposing) return;
switch (event.code) {
case 'ArrowDown':
this.onArrowDownKey(event);
@ -699,6 +703,7 @@ export default {
this.unbindScrollListener();
this.unbindResizeListener();
this.autoFilterFocus && focus(this.$refs.focusInput);
this.$emit('hide');
this.overlay = null;
},

View File

@ -28,7 +28,6 @@
<li
v-if="isItemVisible(item)"
:id="`${id}_${index}`"
:aria-controls="`${id}_item`"
:class="cx('item', { id: `${id}_${index}` })"
:style="getItemStyle(index)"
role="none"

View File

@ -19,7 +19,7 @@ export default {
default: false
},
as: {
type: String,
type: [String, Object],
default: 'DIV'
}
},

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { VNode } from 'vue';
import type { Component, VNode } from 'vue';
export declare type StepPassThroughOptionType = StepPassThroughAttributes | ((options: StepPassThroughMethodOptions) => StepPassThroughAttributes | string) | string | null | undefined;
@ -93,7 +93,7 @@ export interface StepProps {
* Use to change the HTML tag of root element.
* @defaultValue BUTTON
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false

View File

@ -15,7 +15,7 @@ export default {
default: false
},
as: {
type: String,
type: [String, Object],
default: 'DIV'
}
},

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { VNode } from 'vue';
import type { Component, VNode } from 'vue';
export declare type StepPanelPassThroughOptionType = StepPanelPassThroughAttributes | ((options: StepPanelPassThroughMethodOptions) => StepPanelPassThroughAttributes | string) | string | null | undefined;
@ -72,7 +72,7 @@ export interface StepPanelProps {
* Use to change the HTML tag of root element.
* @defaultValue BUTTON
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false
@ -117,7 +117,7 @@ export interface StepPanelSlots {
/**
* Click function.
*/
activateCallback: () => void;
activateCallback: (value: string | number) => void;
}): VNode[];
}

View File

@ -44,6 +44,10 @@ export interface StyleClassOptions {
* Style class to add when leave animation is completed.
*/
leaveToClass?: string | undefined;
/**
* Special class name to hide an element, only used in slide animation.
*/
hiddenClass?: string | undefined;
/**
* Whether to trigger leave animation when outside of the element is clicked.
* @defaultValue false

View File

@ -43,9 +43,9 @@ const StyleClass = BaseStyleClass.extend('styleclass', {
if (binding.value.enterActiveClass.includes('slidedown')) {
target.style.height = '0px';
removeClass(target, 'hidden');
removeClass(target, binding.value.hiddenClass || binding.value.enterFromClass);
target.style.maxHeight = target.scrollHeight + 'px';
addClass(target, 'hidden');
addClass(target, binding.value.hiddenClass || binding.value.enterActiveClass);
target.style.height = '';
}

View File

@ -7,7 +7,7 @@ export default {
extends: BaseComponent,
props: {
value: {
type: String,
type: [String, Number],
default: undefined
},
disabled: {
@ -15,7 +15,7 @@ export default {
default: false
},
as: {
type: String,
type: [String, Object],
default: 'BUTTON'
},
asChild: {

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { VNode } from 'vue';
import type { Component, VNode } from 'vue';
export declare type TabPassThroughOptionType = TabPassThroughAttributes | ((options: TabPassThroughMethodOptions) => TabPassThroughAttributes | string) | string | null | undefined;
@ -71,7 +71,7 @@ export interface TabProps {
/**
* Value of tab.
*/
value: string;
value: string | number;
/**
* Whether the tab is disabled.
* @defaultValue false
@ -81,7 +81,7 @@ export interface TabProps {
* Use to change the HTML tag of root element.
* @defaultValue BUTTON
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false

View File

@ -8,11 +8,11 @@ export default {
props: {
// in Tabs
value: {
type: String,
type: [String, Number],
default: undefined
},
as: {
type: String,
type: [String, Object],
default: 'DIV'
},
asChild: {

View File

@ -10,7 +10,7 @@
import type { DefineComponent, DesignToken, EmitFn, GlobalComponentConstructor, PassThrough } from '@primevue/core';
import type { ComponentHooks } from '@primevue/core/basecomponent';
import type { PassThroughOptions } from 'primevue/passthrough';
import { AnchorHTMLAttributes, HTMLAttributes, LiHTMLAttributes, VNode } from 'vue';
import type { AnchorHTMLAttributes, Component, HTMLAttributes, LiHTMLAttributes, VNode } from 'vue';
export declare type TabPanelPassThroughOptionType = TabPanelPassThroughAttributes | ((options: TabPanelPassThroughMethodOptions) => TabPanelPassThroughAttributes | string) | string | null | undefined;
@ -91,12 +91,12 @@ export interface TabPanelProps {
/**
* Value of tabpanel.
*/
value: string;
value: string | number;
/**
* Use to change the HTML tag of root element.
* @defaultValue DIV
*/
as?: string | undefined;
as?: string | Component | undefined;
/**
* When enabled, it changes the default rendered element for the one passed as a child element.
* @defaultValue false

View File

@ -7,7 +7,7 @@ export default {
extends: BaseComponent,
props: {
value: {
type: String,
type: [String, Number],
default: undefined
},
lazy: {

View File

@ -88,7 +88,7 @@ export interface TabsProps {
/**
* Value of the active tab.
*/
value: string;
value: string | number;
/**
* When enabled, hidden tabs are not rendered at all. Defaults to false that hides tabs with css.
* @defaultValue false

Some files were not shown because too many files have changed in this diff Show More