Merge branch 'master' into v4

pull/5507/head
Cagatay Civici 2024-02-17 14:00:53 +03:00
commit a3725abc1e
235 changed files with 30881 additions and 9546 deletions

View File

@ -270,6 +270,11 @@
"name": "Splitter",
"to": "/splitter"
},
{
"name": "Stepper",
"to": "/stepper",
"badge": "NEW"
},
{
"name": "TabView",
"to": "/tabview"

View File

@ -79,7 +79,7 @@ import ThemeSwitcher from './components/ThemeSwitcher.vue';`;
} else {
// main.js
pvTheme += `import "primeflex/primeflex.css";
import "primevue/resources/themes/lara-light-green/theme.css";`;
import "primevue/resources/themes/aura-light-green/theme.css";`;
// package.json
dependencies['primeflex'] = app_dependencies['primeflex'] || 'latest';
@ -155,6 +155,7 @@ import Badge from 'primevue/badge';
import BadgeDirective from "primevue/badgedirective";
import BlockUI from 'primevue/blockui';
import Button from 'primevue/button';
import ButtonGroup from 'primevue/buttongroup';
import Breadcrumb from 'primevue/breadcrumb';
import Calendar from 'primevue/calendar';
import Card from 'primevue/card';
@ -202,6 +203,7 @@ import MegaMenu from 'primevue/megamenu';
import Menu from 'primevue/menu';
import Menubar from 'primevue/menubar';
import Message from 'primevue/message';
import MeterGroup from 'primevue/metergroup';
import MultiSelect from 'primevue/multiselect';
import OrderList from 'primevue/orderlist';
import OrganizationChart from 'primevue/organizationchart';
@ -227,6 +229,8 @@ import SpeedDial from 'primevue/speeddial';
import SplitButton from 'primevue/splitbutton';
import Splitter from 'primevue/splitter';
import SplitterPanel from 'primevue/splitterpanel';
import Stepper from 'primevue/stepper';
import StepperPanel from 'primevue/stepperpanel';
import Steps from 'primevue/steps';
import StyleClass from 'primevue/styleclass';
import TabMenu from 'primevue/tabmenu';
@ -273,6 +277,7 @@ app.component('Badge', Badge);
app.component('BlockUI', BlockUI);
app.component('Breadcrumb', Breadcrumb);
app.component('Button', Button);
app.component('ButtonGroup', ButtonGroup);
app.component('Calendar', Calendar);
app.component('Card', Card);
app.component('Carousel', Carousel);
@ -316,6 +321,7 @@ app.component('MegaMenu', MegaMenu);
app.component('Menu', Menu);
app.component('Menubar', Menubar);
app.component('Message', Message);
app.component('MeterGroup', MeterGroup);
app.component('MultiSelect', MultiSelect);
app.component('OrderList', OrderList);
app.component('OrganizationChart', OrganizationChart);
@ -340,6 +346,8 @@ app.component('SpeedDial', SpeedDial);
app.component('SplitButton', SplitButton);
app.component('Splitter', Splitter);
app.component('SplitterPanel', SplitterPanel);
app.component('Stepper', Stepper);
app.component('StepperPanel', StepperPanel);
app.component('Steps', Steps);
app.component('TabMenu', TabMenu);
app.component('TabView', TabView);

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<div v-for="(tab, i) of tabs" :key="getKey(tab, i)" :class="cx('tab.root', { tab, index: i })" v-bind="getTabPT(tab, 'root', i)" data-pc-name="accordiontab" :data-pc-index="i" :data-p-active="isTabActive(i)">
<div
:style="getTabProp(tab, 'headerStyle')"
@ -64,6 +64,7 @@ import BaseAccordion from './BaseAccordion.vue';
export default {
name: 'Accordion',
extends: BaseAccordion,
inheritAttrs: false,
emits: ['update:activeIndex', 'tab-open', 'tab-close', 'tab-click'],
data() {
return {

View File

@ -7,6 +7,7 @@ import BaseAccordionTab from './BaseAccordionTab.vue';
export default {
name: 'AccordionTab',
extends: BaseAccordionTab
extends: BaseAccordionTab,
inheritAttrs: false
};
</script>

View File

@ -20,6 +20,7 @@
:aria-expanded="overlayVisible"
:aria-controls="id + '_list'"
:aria-activedescendant="focused ? focusedOptionId : undefined"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@keydown="onKeyDown"
@ -78,6 +79,7 @@
:aria-expanded="overlayVisible"
:aria-controls="id + '_list'"
:aria-activedescendant="focused ? focusedOptionId : undefined"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@keydown="onKeyDown"

View File

@ -1,12 +1,13 @@
/**
*
* AvatarGroup is a helper component for Avatar.
* A set of Avatars can be displayed together using the AvatarGroup component.
*
* [Live Demo](https://www.primevue.org/accordion/)
*
* @module avatargroup
*
*/
import { VNode } from 'vue';
import { ComponentHooks } from '../basecomponent';
import { PassThroughOptions } from '../passthrough';
import { ClassComponent, GlobalComponentConstructor, PassThrough } from '../ts-helpers';
@ -60,7 +61,12 @@ export interface AvatarGroupProps {
/**
* Defines valid slots in AvatarGroup component.
*/
export interface AvatarGroupSlots {}
export interface AvatarGroupSlots {
/**
* Default slot to detect Avatar components.
*/
default(): VNode[];
}
/**
* Defines valid emits in AvatarGroup component.

View File

@ -0,0 +1,15 @@
<script>
import BaseComponent from 'primevue/basecomponent';
import ButtonGroupStyle from 'primevue/buttongroup/style';
export default {
name: 'BaseButtonGroup',
extends: BaseComponent,
style: ButtonGroupStyle,
provide() {
return {
$parentInstance: this
};
}
};
</script>

View File

@ -0,0 +1,113 @@
/**
*
* A set of Buttons can be displayed together using the ButtonGroup component.
*
* [Live Demo](https://www.primevue.org/button/)
*
* @module buttongroup
*
*/
import { VNode } from 'vue';
import { ComponentHooks } from '../basecomponent/BaseComponent';
import { PassThroughOptions } from '../passthrough';
import { ClassComponent, GlobalComponentConstructor, PassThrough } from '../ts-helpers';
export declare type ButtonGroupPassThroughOptionType = ButtonGroupPassThroughAttributes | ((options: ButtonGroupPassThroughMethodOptions) => ButtonGroupPassThroughAttributes | string) | string | null | undefined;
/**
* Custom passthrough(pt) option method.
*/
export interface ButtonGroupPassThroughMethodOptions {
/**
* Defines instance.
*/
instance: any;
/**
* Defines valid properties.
*/
props: ButtonGroupProps;
/**
* Defines passthrough(pt) options in global config.
*/
global: object | undefined;
}
/**
* Custom passthrough(pt) options.
* @see {@link ButtonGroupProps.pt}
*/
export interface ButtonGroupPassThroughOptions {
/**
* Used to pass attributes to the root's DOM element.
*/
root?: ButtonGroupPassThroughOptionType;
/**
* Used to manage all lifecycle hooks.
* @see {@link BaseComponent.ComponentHooks}
*/
hooks?: ComponentHooks;
}
/**
* Custom passthrough attributes for each DOM elements
*/
export interface ButtonGroupPassThroughAttributes {
[key: string]: any;
}
/**
* Defines valid properties in ButtonGroup component.
*/
export interface ButtonGroupProps {
/**
* Used to pass attributes to DOM elements inside the component.
* @type {ButtonGroupPassThroughOptions}
*/
pt?: PassThrough<ButtonGroupPassThroughOptions>;
/**
* Used to configure passthrough(pt) options of the component.
* @type {PassThroughOptions}
*/
ptOptions?: PassThroughOptions;
/**
* When enabled, it removes component related styles in the core.
* @defaultValue false
*/
unstyled?: boolean;
}
/**
* Defines valid slots in ButtonGroup component.
*/
export interface ButtonGroupSlots {
/**
* Default slot to detect Button components.
*/
default(): VNode[];
}
/**
* Defines valid emits in ButtonGroup component.
*/
export interface ButtonGroupEmits {}
/**
* **PrimeVue - ButtonGroup**
*
* _A set of Buttons can be displayed together using the ButtonGroup component._
*
* [Live Demo](https://www.primevue.org/button/)
* --- ---
* ![PrimeVue](https://primefaces.org/cdn/primevue/images/logo-100.png)
*
* @group Component
*/
declare class ButtonGroup extends ClassComponent<ButtonGroupProps, ButtonGroupSlots, ButtonGroupEmits> {}
declare module '@vue/runtime-core' {
interface GlobalComponents {
ButtonGroup: GlobalComponentConstructor<ButtonGroup>;
}
}
export default ButtonGroup;

View File

@ -0,0 +1,15 @@
<template>
<span :class="cx('root')" role="group" v-bind="ptmi('root')">
<slot />
</span>
</template>
<script>
import BaseButtonGroup from './BaseButtonGroup.vue';
export default {
name: 'ButtonGroup',
extends: BaseButtonGroup,
inheritAttrs: false
};
</script>

View File

@ -0,0 +1,9 @@
{
"main": "./buttongroup.cjs.js",
"module": "./buttongroup.esm.js",
"unpkg": "./buttongroup.min.js",
"types": "./ButtonGroup.d.ts",
"browser": {
"./sfc": "./ButtonGroup.vue"
}
}

View File

@ -0,0 +1,3 @@
import { BaseStyle } from '../../base/style/BaseStyle';
export interface ButtonGroupStyle extends BaseStyle {}

View File

@ -0,0 +1,10 @@
import BaseStyle from 'primevue/base/style';
const classes = {
root: 'p-button-group p-component'
};
export default BaseStyle.extend({
name: 'buttongroup',
classes
});

View File

@ -0,0 +1,6 @@
{
"main": "./buttongroupstyle.cjs.js",
"module": "./buttongroupstyle.esm.js",
"unpkg": "./buttongroupstyle.min.js",
"types": "./ButtonGroupStyle.d.ts"
}

View File

@ -16,6 +16,7 @@
:aria-controls="panelId"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-invalid="invalid || undefined"
inputmode="none"
:disabled="disabled"
:readonly="!manualInput || readonly"
@ -1809,7 +1810,7 @@ export default {
let parts = text.split(' ');
if (this.timeOnly) {
date = new Date(this.modelValue);
date = new Date();
this.populateTime(date, parts[0], parts[1]);
} else {
const dateFormat = this.datePattern;

View File

@ -9,7 +9,7 @@ const classes = {
'p-calendar p-component p-inputwrapper',
{
'p-calendar-w-btn': props.showIcon && props.iconDisplay === 'button',
'p-input-icon-right': props.showIcon && props.iconDisplay === 'input',
'p-icon-field p-icon-field-right': props.showIcon && props.iconDisplay === 'input',
'p-calendar-timeonly': props.timeOnly,
'p-calendar-disabled': props.disabled,
'p-invalid': props.invalid,
@ -25,7 +25,7 @@ const classes = {
}
],
dropdownButton: 'p-datepicker-trigger',
inputIcon: 'p-datepicker-trigger-icon',
inputIcon: 'p-datepicker-trigger-icon p-input-icon',
panel: ({ instance, props, state }) => [
'p-datepicker p-component',
{

View File

@ -18,6 +18,7 @@
:aria-expanded="overlayVisible"
:aria-controls="id + '_tree'"
:aria-activedescendant="focused ? focusedOptionId : undefined"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@keydown="onKeyDown"
@ -283,13 +284,24 @@ export default {
const { index, level, parentKey, children } = processedOption;
const grouped = ObjectUtils.isNotEmpty(children);
const root = ObjectUtils.isEmpty(processedOption.parent);
const selected = this.isSelected(processedOption);
const activeOptionPath = this.activeOptionPath.filter((p) => p.parentKey !== parentKey);
if (selected) {
const { index, key, level, parentKey } = processedOption;
activeOptionPath.push(processedOption);
this.focusedOptionInfo = { index, level, parentKey };
this.activeOptionPath = this.activeOptionPath.filter((p) => key !== p.key && key.startsWith(p.key));
this.focusedOptionInfo = { index, level, parentKey };
this.activeOptionPath = activeOptionPath;
this.dirty = !root;
} else {
const activeOptionPath = this.activeOptionPath.filter((p) => p.parentKey !== parentKey);
activeOptionPath.push(processedOption);
this.focusedOptionInfo = { index, level, parentKey };
this.activeOptionPath = activeOptionPath;
}
grouped ? this.onOptionGroupSelect(originalEvent, processedOption) : this.onOptionSelect(originalEvent, processedOption, isHide);
isFocus && DomHandler.focus(this.$refs.focusInput);

View File

@ -14,6 +14,7 @@
:required="required"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@change="onChange"

View File

@ -44,6 +44,7 @@
:style="inputStyle"
:disabled="disabled || maxedOut"
:placeholder="placeholder"
:aria-invalid="invalid || undefined"
@focus="onFocus($event)"
@blur="onBlur($event)"
@input="onInput"

View File

@ -4,6 +4,7 @@ import BaseColumn from './BaseColumn.vue';
export default {
name: 'Column',
extends: BaseColumn,
inheritAttrs: false,
inject: ['$columns'],
mounted() {
this.$columns?.add(this.$);

View File

@ -4,6 +4,7 @@ import BaseColumnGroup from './BaseColumnGroup.vue';
export default {
name: 'ColumnGroup',
extends: BaseColumnGroup,
inheritAttrs: false,
inject: ['$columnGroups'],
mounted() {
this.$columnGroups?.add(this.$);

View File

@ -1,7 +1,7 @@
<template>
<Portal>
<transition name="p-confirm-popup" @enter="onEnter" @after-enter="onAfterEnter" @leave="onLeave" @after-leave="onAfterLeave" v-bind="ptm('transition')">
<div v-if="visible" :ref="containerRef" v-focustrap role="alertdialog" :class="cx('root')" :aria-modal="visible" @click="onOverlayClick" @keydown="onOverlayKeydown" v-bind="{ ...$attrs, ...ptm('root') }">
<div v-if="visible" :ref="containerRef" v-focustrap role="alertdialog" :class="cx('root')" :aria-modal="visible" @click="onOverlayClick" @keydown="onOverlayKeydown" v-bind="ptmi('root')">
<slot v-if="$slots.container" name="container" :message="confirmation" :onAccept="accept" :onReject="reject" :acceptCallback="accept" :rejectCallback="reject"></slot>
<template v-else>
<template v-if="!$slots.message">

View File

@ -1,7 +1,7 @@
<template>
<Portal :appendTo="appendTo">
<transition name="p-contextmenu" @enter="onEnter" @after-enter="onAfterEnter" @leave="onLeave" @after-leave="onAfterLeave" v-bind="ptm('transition')">
<div v-if="visible" :ref="containerRef" :class="cx('root')" v-bind="{ ...$attrs, ...ptm('root') }">
<div v-if="visible" :ref="containerRef" :class="cx('root')" v-bind="ptmi('root')">
<ContextMenuSub
:ref="listRef"
:id="id + '_list'"
@ -27,6 +27,7 @@
@keydown="onKeyDown"
@item-click="onItemClick"
@item-mouseenter="onItemMouseEnter"
@item-mousemove="onItemMouseMove"
/>
</div>
</transition>
@ -247,6 +248,11 @@ export default {
onItemMouseEnter(event) {
this.onItemChange(event);
},
onItemMouseMove(event) {
if (this.focused) {
this.changeFocusedItemIndex(event, event.processedItem.index);
}
},
onArrowDownKey(event) {
const itemIndex = this.focusedItemInfo.index !== -1 ? this.findNextItemIndex(this.focusedItemInfo.index) : this.findFirstFocusedItemIndex();

View File

@ -20,10 +20,16 @@
:data-p-focused="isItemFocused(processedItem)"
:data-p-disabled="isItemDisabled(processedItem)"
>
<div :class="cx('content')" @click="onItemClick($event, processedItem)" @mouseenter="onItemMouseEnter($event, processedItem)" v-bind="getPTOptions('content', processedItem, index)">
<div
:class="cx('content')"
@click="onItemClick($event, processedItem)"
@mouseenter="onItemMouseEnter($event, processedItem)"
@mousemove="onItemMouseMove($event, processedItem)"
v-bind="getPTOptions('content', processedItem, index)"
>
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('action')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions('action', processedItem, index)">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" />
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="cx('icon')" />
<span v-else-if="getItemProp(processedItem, 'icon')" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" v-bind="getPTOptions('icon', processedItem, index)" />
<span :id="getItemLabelId(processedItem)" :class="cx('label')" v-bind="getPTOptions('label', processedItem, index)">{{ getItemLabel(processedItem) }}</span>
<template v-if="getItemProp(processedItem, 'items')">
@ -50,6 +56,7 @@
:unstyled="unstyled"
@item-click="$emit('item-click', $event)"
@item-mouseenter="$emit('item-mouseenter', $event)"
@item-mousemove="$emit('item-mousemove', $event)"
:aria-labelledby="getItemLabelId(processedItem)"
v-bind="ptm('submenu')"
/>
@ -78,7 +85,7 @@ export default {
name: 'ContextMenuSub',
hostName: 'ContextMenu',
extends: BaseComponent,
emits: ['item-click', 'item-mouseenter'],
emits: ['item-click', 'item-mouseenter', 'item-mousemove'],
props: {
items: {
type: Array,
@ -166,6 +173,9 @@ export default {
onItemMouseEnter(event, processedItem) {
this.$emit('item-mouseenter', { originalEvent: event, processedItem });
},
onItemMouseMove(event, processedItem) {
this.$emit('item-mousemove', { originalEvent: event, processedItem, isFocus: true });
},
getAriaSetSize() {
return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length;
},

View File

@ -425,9 +425,6 @@ export default {
return null;
}
},
isEditingCellValid() {
return DomHandler.find(this.$el, '.p-invalid').length === 0;
},
onRowEditInit(event) {
this.$emit('row-edit-init', { originalEvent: event, data: this.rowData, newData: this.editingRowData, field: this.field, index: this.rowIndex });
},

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" data-scrollselectors=".p-datatable-wrapper" v-bind="ptm('root')">
<div :class="cx('root')" data-scrollselectors=".p-datatable-wrapper" v-bind="ptmi('root')">
<slot></slot>
<div v-if="loading" :class="cx('loadingOverlay')" v-bind="ptm('loadingOverlay')">
<slot v-if="$slots.loading" name="loading"></slot>
@ -293,6 +293,7 @@ import TableHeader from './TableHeader.vue';
export default {
name: 'DataTable',
extends: BaseDataTable,
inheritAttrs: false,
emits: [
'value-change',
'update:first',
@ -863,13 +864,14 @@ export default {
break;
default:
if (event.code === 'KeyA' && metaKey) {
if (event.code === 'KeyA' && metaKey && this.isMultipleSelectionMode()) {
const data = this.dataToRender(slotProps.rows);
this.$emit('update:selection', data);
event.preventDefault();
}
event.preventDefault();
break;
}
}

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<div v-if="$slots.header" :class="cx('header')" v-bind="ptm('header')">
<slot name="header"></slot>
</div>
@ -72,6 +72,7 @@ import BaseDataView from './BaseDataView.vue';
export default {
name: 'DataView',
extends: BaseDataView,
inheritAttrs: false,
emits: ['update:first', 'update:rows', 'page'],
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" role="group" v-bind="ptm('root')">
<div :class="cx('root')" role="group" v-bind="ptmi('root')">
<button :aria-label="listViewAriaLabel" :class="cx('listButton')" @click="changeLayout('list')" type="button" :aria-pressed="isListButtonPressed" v-bind="ptm('listButton')">
<slot name="listicon">
<BarsIcon v-bind="ptm('listIcon')" />
@ -21,6 +21,7 @@ import BaseDataViewLayoutOptions from './BaseDataViewLayoutOptions.vue';
export default {
name: 'DataViewLayoutOptions',
extends: BaseDataViewLayoutOptions,
inheritAttrs: false,
emits: ['update:modelValue'],
data() {
return {

View File

@ -1,7 +1,7 @@
import BaseStyle from 'primevue/base/style';
const classes = {
root: 'p-dataview-layout-options p-selectbutton p-buttonset',
root: 'p-dataview-layout-options p-selectbutton p-button-group',
listButton: ({ props }) => [
'p-button p-button-icon-only',
{

View File

@ -1,5 +1,5 @@
<template>
<div ref="container" v-bind="ptm('root')">
<div ref="container" v-bind="ptmi('root')">
<slot v-if="loaded"></slot>
</div>
</template>
@ -11,6 +11,7 @@ import DeferredContentStyle from 'primevue/deferredcontent/style';
export default {
name: 'DeferredContent',
extends: BaseComponent,
inheritAttrs: false,
emits: ['load'],
style: DeferredContentStyle,
data() {

View File

@ -2,7 +2,7 @@
<Portal :appendTo="appendTo">
<div v-if="containerVisible" :ref="maskRef" :class="cx('mask')" :style="sx('mask', true, { position, modal })" @click="onMaskClick" 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')">
<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="{ ...$attrs, ...ptm('root') }">
<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" :onClose="close" :onMaximize="(event) => maximize(event)" :closeCallback="close" :maximizeCallback="(event) => maximize(event)"></slot>
<template v-else>
<div v-if="showHeader" :ref="headerContainerRef" :class="cx('header')" @mousedown="initDrag" v-bind="ptm('header')">
@ -301,7 +301,7 @@ export default {
this.lastPageY = event.pageY;
this.container.style.margin = '0';
document.body.setAttribute('data-p-unselectable-text', '');
document.body.setAttribute('data-p-unselectable-text', 'true');
!this.isUnstyled && DomHandler.addClass(document.body, 'p-unselectable-text');
}
},

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" :style="sx('root')" role="separator" :aria-orientation="layout" v-bind="ptm('root')">
<div :class="cx('root')" :style="sx('root')" role="separator" :aria-orientation="layout" v-bind="ptmi('root')">
<div v-if="$slots.default" :class="cx('content')" v-bind="ptm('content')">
<slot></slot>
</div>
@ -11,6 +11,7 @@ import BaseDivider from './BaseDivider.vue';
export default {
name: 'Divider',
extends: BaseDivider
extends: BaseDivider,
inheritAttrs: false
};
</script>

View File

@ -19,6 +19,7 @@
:aria-expanded="overlayVisible"
:aria-controls="id + '_list'"
:aria-activedescendant="focused ? focusedOptionId : undefined"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@keydown="onKeyDown"

View File

@ -76,7 +76,7 @@ export default {
emits: ['activeitem-change', 'mask-hide'],
data() {
return {
id: this.$attrs.id,
id: this.$attrs.id || UniqueComponentId(),
activeIndex: this.$attrs.activeIndex,
numVisible: this.$attrs.numVisible,
slideShowActive: false

View File

@ -2,9 +2,10 @@ import BaseStyle from 'primevue/base/style';
const classes = {
root: ({ props }) => [
'p-icon-field',
{
'p-input-icon-right': props.iconPosition === 'right',
'p-input-icon-left': props.iconPosition === 'left'
'p-icon-field-right': props.iconPosition === 'right',
'p-icon-field-left': props.iconPosition === 'left'
}
]
};

View File

@ -6,6 +6,9 @@ export default {
name: 'BaseInputIcon',
extends: BaseComponent,
style: InputIconStyle,
props: {
class: null
},
provide() {
return {
$parentInstance: this

View File

@ -1,5 +1,7 @@
<template>
<slot />
<span :class="containerClass" v-bind="ptmi('root')">
<slot />
</span>
</template>
<script>
@ -7,6 +9,12 @@ import BaseInputIcon from './BaseInputIcon.vue';
export default {
name: 'InputIcon',
extends: BaseInputIcon
extends: BaseInputIcon,
inheritAttrs: false,
computed: {
containerClass() {
return [this.cx('root'), this.class];
}
}
};
</script>

View File

@ -1 +1,10 @@
export default {};
import BaseStyle from 'primevue/base/style';
const classes = {
root: 'p-input-icon'
};
export default BaseStyle.extend({
name: 'inputicon',
classes
});

View File

@ -1,5 +1,5 @@
<template>
<input :class="cx('root')" :readonly="readonly" @input="onInput" @focus="onFocus" @blur="onBlur" @keydown="onKeyDown" @keypress="onKeyPress" @paste="onPaste" v-bind="ptmi('root', ptmParams)" />
<input :class="cx('root')" :readonly="readonly" :aria-invalid="invalid || undefined" @input="onInput" @focus="onFocus" @blur="onBlur" @keydown="onKeyDown" @keypress="onKeyPress" @paste="onPaste" v-bind="ptmi('root', ptmParams)" />
</template>
<script>

View File

@ -15,6 +15,7 @@
:placeholder="placeholder"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-invalid="invalid || undefined"
@input="onUserInput"
@keydown="onInputKeyDown"
@keypress="onInputKeyPress"

View File

@ -13,6 +13,7 @@
:aria-checked="checked"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@change="onChange"

View File

@ -1,5 +1,5 @@
<template>
<input :class="cx('root')" :value="modelValue" @input="onInput" v-bind="getPTOptions('root')" />
<input :class="cx('root')" :value="modelValue" :aria-invalid="invalid || undefined" @input="onInput" v-bind="getPTOptions('root')" />
</template>
<script>
@ -8,10 +8,13 @@ import BaseInputText from './BaseInputText.vue';
export default {
name: 'InputText',
extends: BaseInputText,
inheritAttrs: false,
emits: ['update:modelValue'],
methods: {
getPTOptions(key) {
return this.ptm(key, {
const _ptm = key === 'root' ? this.ptmi : this.ptm;
return _ptm(key, {
context: {
filled: this.filled,
disabled: this.$attrs.disabled || this.$attrs.disabled === ''

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<svg
viewBox="0 0 100 100"
role="slider"
@ -35,6 +35,7 @@ const Math_PI = 3.14159265358979;
export default {
name: 'Knob',
extends: BaseKnob,
inheritAttrs: false,
emits: ['update:modelValue', 'change'],
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<div :id="id" :class="cx('root')" @focusout="onFocusout" v-bind="ptm('root')">
<div :id="id" :class="cx('root')" @focusout="onFocusout" v-bind="ptmi('root')">
<span
ref="firstHiddenFocusableElement"
role="presentation"
@ -132,6 +132,7 @@ import BaseListbox from './BaseListbox.vue';
export default {
name: 'Listbox',
extends: BaseListbox,
inheritAttrs: false,
emits: ['update:modelValue', 'change', 'focus', 'blur', 'filter'],
list: null,
virtualScroller: null,

View File

@ -1,5 +1,5 @@
<template>
<div :ref="containerRef" :id="id" :class="cx('root')" v-bind="ptm('root')">
<div :ref="containerRef" :id="id" :class="cx('root')" v-bind="ptmi('root')">
<div v-if="$slots.start" :class="cx('start')" v-bind="ptm('start')">
<slot name="start"></slot>
</div>
@ -64,6 +64,7 @@ import MegaMenuSub from './MegaMenuSub.vue';
export default {
name: 'MegaMenu',
extends: BaseMegaMenu,
inheritAttrs: false,
emits: ['focus', 'blur'],
outsideClickListener: null,
resizeListener: null,

View File

@ -23,7 +23,7 @@
<div :class="cx('content')" @click="onItemClick($event, processedItem)" @mouseenter="onItemMouseEnter($event, processedItem)" v-bind="getPTOptions(processedItem, index, 'content')">
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('action')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions(processedItem, index, 'action')">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" />
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="cx('icon')" />
<span v-else-if="getItemProp(processedItem, 'icon')" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" v-bind="getPTOptions(processedItem, index, 'icon')" />
<span :class="level === 0 ? cx('label') : cx('submenuLabel')" v-bind="level === 0 ? getPTOptions(processedItem, index, 'label') : getPTOptions(processedItem, index, 'submenuLabel')">{{ getItemLabel(processedItem) }}</span>
<template v-if="isItemGroup(processedItem)">

View File

@ -1,7 +1,7 @@
<template>
<Portal :appendTo="appendTo" :disabled="!popup">
<transition name="p-connected-overlay" @enter="onEnter" @leave="onLeave" @after-leave="onAfterLeave" v-bind="ptm('transition')">
<div v-if="popup ? overlayVisible : true" :ref="containerRef" :id="id" :class="cx('root')" @click="onOverlayClick" v-bind="{ ...$attrs, ...ptm('root') }">
<div v-if="popup ? overlayVisible : true" :ref="containerRef" :id="id" :class="cx('root')" @click="onOverlayClick" v-bind="ptmi('root')">
<div v-if="$slots.start" :class="cx('start')" v-bind="ptm('start')">
<slot name="start"></slot>
</div>
@ -25,12 +25,21 @@
<slot name="submenuheader" :item="item">{{ label(item) }}</slot>
</li>
<template v-for="(child, j) of item.items" :key="child.label + i + '_' + j">
<PVMenuitem v-if="visible(child) && !child.separator" :id="id + '_' + i + '_' + j" :item="child" :templates="$slots" :focusedOptionId="focusedOptionId" @item-click="itemClick" :pt="pt" />
<PVMenuitem
v-if="visible(child) && !child.separator"
:id="id + '_' + i + '_' + j"
:item="child"
:templates="$slots"
:focusedOptionId="focusedOptionId"
@item-click="itemClick"
@item-mousemove="itemMouseMove"
:pt="pt"
/>
<li v-else-if="visible(child) && child.separator" :key="'separator' + i + j" :class="[cx('separator'), item.class]" :style="child.style" role="separator" v-bind="ptm('separator')"></li>
</template>
</template>
<li v-else-if="visible(item) && item.separator" :key="'separator' + i.toString()" :class="[cx('separator'), item.class]" :style="item.style" role="separator" v-bind="ptm('separator')"></li>
<PVMenuitem v-else :key="label(item) + i.toString()" :id="id + '_' + i" :item="item" :index="i" :templates="$slots" :focusedOptionId="focusedOptionId" @item-click="itemClick" :pt="pt" />
<PVMenuitem v-else :key="label(item) + i.toString()" :id="id + '_' + i" :item="item" :index="i" :templates="$slots" :focusedOptionId="focusedOptionId" @item-click="itemClick" @item-mousemove="itemMouseMove" :pt="pt" />
</template>
</ul>
<div v-if="$slots.end" :class="cx('end')" v-bind="ptm('end')">
@ -116,15 +125,14 @@ export default {
this.focusedOptionIndex = event.id;
}
},
itemMouseMove(event) {
if (this.focused) {
this.focusedOptionIndex = event.id;
}
},
onListFocus(event) {
this.focused = true;
if (!this.popup) {
if (this.selectedOptionIndex !== -1) {
this.changeFocusedOptionIndex(this.selectedOptionIndex);
this.selectedOptionIndex = -1;
} else this.changeFocusedOptionIndex(0);
}
!this.popup && this.changeFocusedOptionIndex(0);
this.$emit('focus', event);
},
@ -255,7 +263,6 @@ export default {
if (this.popup) {
DomHandler.focus(this.list);
this.changeFocusedOptionIndex(0);
}
this.$emit('show');

View File

@ -11,10 +11,10 @@
:data-p-focused="isItemFocused()"
:data-p-disabled="disabled() || false"
>
<div :class="cx('content')" @click="onItemClick($event)" v-bind="getPTOptions('content')">
<div :class="cx('content')" @click="onItemClick($event)" @mousemove="onItemMouseMove($event)" v-bind="getPTOptions('content')">
<template v-if="!templates.item">
<a v-ripple :href="item.url" :class="cx('action')" :target="item.target" tabindex="-1" aria-hidden="true" v-bind="getPTOptions('action')">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="item" :class="[cx('icon'), item.icon]" />
<component v-if="templates.itemicon" :is="templates.itemicon" :item="item" :class="cx('icon')" />
<span v-else-if="item.icon" :class="[cx('icon'), item.icon]" v-bind="getPTOptions('icon')" />
<span :class="cx('label')" v-bind="getPTOptions('label')">{{ label() }}</span>
</a>
@ -35,7 +35,7 @@ export default {
hostName: 'Menu',
extends: BaseComponent,
inheritAttrs: false,
emits: ['item-click'],
emits: ['item-click', 'item-mousemove'],
props: {
item: null,
templates: null,
@ -66,6 +66,9 @@ export default {
command && command({ originalEvent: event, item: this.item.item });
this.$emit('item-click', { originalEvent: event, item: this.item, id: this.id });
},
onItemMouseMove(event) {
this.$emit('item-mousemove', { originalEvent: event, item: this.item, id: this.id });
},
visible() {
return typeof this.item.visible === 'function' ? this.item.visible() : this.item.visible !== false;
},

View File

@ -1,5 +1,5 @@
<template>
<div :ref="containerRef" :class="cx('root')" v-bind="ptm('root')">
<div :ref="containerRef" :class="cx('root')" v-bind="ptmi('root')">
<div v-if="$slots.start" :class="cx('start')" v-bind="ptm('start')">
<slot name="start"></slot>
</div>
@ -46,6 +46,7 @@
@keydown="onKeyDown"
@item-click="onItemClick"
@item-mouseenter="onItemMouseEnter"
@item-mousemove="onItemMouseMove"
/>
<div v-if="$slots.end" :class="cx('end')" v-bind="ptm('end')">
<slot name="end"></slot>
@ -62,6 +63,7 @@ import MenubarSub from './MenubarSub.vue';
export default {
name: 'Menubar',
extends: BaseMenubar,
inheritAttrs: false,
emits: ['focus', 'blur'],
matchMediaListener: null,
data() {
@ -148,8 +150,6 @@ export default {
event.preventDefault();
},
show() {
this.focusedItemInfo = { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' };
DomHandler.focus(this.menubar);
},
hide(event, isFocus) {
@ -168,7 +168,11 @@ export default {
},
onFocus(event) {
this.focused = true;
this.focusedItemInfo = this.focusedItemInfo.index !== -1 ? this.focusedItemInfo : { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' };
if (!this.popup) {
this.focusedItemInfo = this.focusedItemInfo.index !== -1 ? this.focusedItemInfo : { index: this.findFirstFocusedItemIndex(), level: 0, parentKey: '' };
}
this.$emit('focus', event);
},
onBlur(event) {
@ -289,6 +293,11 @@ export default {
this.onItemChange(event);
}
},
onItemMouseMove(event) {
if (this.focused) {
this.changeFocusedItemIndex(event, event.processedItem.index);
}
},
menuButtonClick(event) {
this.toggle(event);
},

View File

@ -19,10 +19,10 @@
:data-p-focused="isItemFocused(processedItem)"
:data-p-disabled="isItemDisabled(processedItem)"
>
<div :class="cx('content')" @click="onItemClick($event, processedItem)" @mouseenter="onItemMouseEnter($event, processedItem)" v-bind="getPTOptions(processedItem, index, 'content')">
<div :class="cx('content')" @click="onItemClick($event, processedItem)" @mouseenter="onItemMouseEnter($event, processedItem)" @mousemove="onItemMouseMove($event, processedItem)" v-bind="getPTOptions(processedItem, index, 'content')">
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('action')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions(processedItem, index, 'action')">
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" />
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="cx('icon')" />
<span v-else-if="getItemProp(processedItem, 'icon')" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" v-bind="getPTOptions(processedItem, index, 'icon')" />
<span :id="getItemLabelId(processedItem)" :class="cx('label')" v-bind="getPTOptions(processedItem, index, 'label')">{{ getItemLabel(processedItem) }}</span>
<template v-if="getItemProp(processedItem, 'items')">
@ -49,6 +49,7 @@
:unstyled="unstyled"
@item-click="$emit('item-click', $event)"
@item-mouseenter="$emit('item-mouseenter', $event)"
@item-mousemove="$emit('item-mousemove', $event)"
/>
</li>
<li
@ -75,7 +76,7 @@ export default {
name: 'MenubarSub',
hostName: 'Menubar',
extends: BaseComponent,
emits: ['item-mouseenter', 'item-click'],
emits: ['item-mouseenter', 'item-click', 'item-mousemove'],
props: {
items: {
type: Array,
@ -165,6 +166,9 @@ export default {
onItemMouseEnter(event, processedItem) {
this.$emit('item-mouseenter', { originalEvent: event, processedItem });
},
onItemMouseMove(event, processedItem) {
this.$emit('item-mousemove', { originalEvent: event, processedItem });
},
getAriaSetSize() {
return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length;
},

View File

@ -1,5 +1,5 @@
<template>
<transition name="p-message" appear v-bind="ptm('transition')">
<transition name="p-message" appear v-bind="ptmi('transition')">
<div v-show="visible" :class="cx('root')" role="alert" aria-live="assertive" aria-atomic="true" v-bind="ptm('root')">
<slot v-if="$slots.container" name="container" :onClose="close" :closeCallback="close"></slot>
<div v-else :class="cx('wrapper')" v-bind="ptm('wrapper')">
@ -32,6 +32,7 @@ import BaseMessage from './BaseMessage.vue';
export default {
name: 'Message',
extends: BaseMessage,
inheritAttrs: false,
emits: ['close', 'life-end'],
timeout: null,
data() {

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" role="meter" :aria-valuemin="min" :aria-valuemax="max" :aria-valuenow="totalPercent" v-bind="ptm('root')">
<div :class="cx('root')" role="meter" :aria-valuemin="min" :aria-valuemax="max" :aria-valuenow="totalPercent" v-bind="ptmi('root')">
<slot v-if="labelPosition === 'start'" name="label" :value="value" :totalPercent="totalPercent" :percentages="percentages">
<MeterGroupLabel :value="value" :labelPosition="labelPosition" :labelOrientation="labelOrientation" :unstyled="unstyled" :pt="pt" />
</slot>
@ -25,6 +25,7 @@ import MeterGroupLabel from './MeterGroupLabel.vue';
export default {
name: 'MeterGroup',
extends: BaseMeterGroup,
inheritAttrs: false,
methods: {
getPTOptions(key, value, index) {
return this.ptm(key, {

View File

@ -1,5 +1,5 @@
<template>
<div ref="container" :class="cx('root')" @click="onContainerClick" v-bind="ptm('root')">
<div ref="container" :class="cx('root')" @click="onContainerClick" v-bind="ptmi('root')">
<div class="p-hidden-accessible" v-bind="ptm('hiddenInputWrapper')" :data-p-hidden-accessible="true">
<input
ref="focusInput"
@ -16,6 +16,7 @@
:aria-expanded="overlayVisible"
:aria-controls="id + '_list'"
:aria-activedescendant="focused ? focusedOptionId : undefined"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@keydown="onKeyDown"
@ -214,6 +215,7 @@ import BaseMultiSelect from './BaseMultiSelect.vue';
export default {
name: 'MultiSelect',
extends: BaseMultiSelect,
inheritAttrs: false,
emits: ['update:modelValue', 'change', 'focus', 'blur', 'before-show', 'before-hide', 'show', 'hide', 'filter', 'selectall-change'],
outsideClickListener: null,
scrollHandler: null,

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<div :class="cx('controls')" v-bind="ptm('controls')">
<slot name="controlsstart"></slot>
<OLButton type="button" @click="moveUp" :aria-label="moveUpAriaLabel" :disabled="moveDisabled()" v-bind="moveUpButtonProps" :pt="ptm('moveUpButton')" :unstyled="unstyled">
@ -90,6 +90,7 @@ import BaseOrderList from './BaseOrderList.vue';
export default {
name: 'OrderList',
extends: BaseOrderList,
inheritAttrs: false,
emits: ['update:modelValue', 'reorder', 'update:selection', 'selection-change', 'focus', 'blur'],
itemTouched: false,
reorderDirection: null,

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<OrganizationChartNode
:node="value"
:templates="$slots"
@ -22,6 +22,7 @@ import OrganizationChartNode from './OrganizationChartNode.vue';
export default {
name: 'OrganizationChart',
extends: BaseOrganizationChart,
inheritAttrs: false,
emits: ['node-unselect', 'node-select', 'update:selectionKeys', 'node-expand', 'node-collapse', 'update:collapsedKeys'],
data() {
return {

View File

@ -1,7 +1,7 @@
<template>
<Portal :appendTo="appendTo">
<transition name="p-overlaypanel" @enter="onEnter" @leave="onLeave" @after-leave="onAfterLeave" v-bind="ptm('transition')">
<div v-if="visible" :ref="containerRef" v-focustrap role="dialog" :aria-modal="visible" @click="onOverlayClick" :class="cx('root')" v-bind="{ ...$attrs, ...ptm('root') }">
<div v-if="visible" :ref="containerRef" v-focustrap role="dialog" :aria-modal="visible" @click="onOverlayClick" :class="cx('root')" v-bind="ptmi('root')">
<slot v-if="$slots.container" name="container" :onClose="hide" :onKeydown="(event) => onButtonKeydown(event)" :closeCallback="hide" :keydownCallback="(event) => onButtonKeydown(event)"></slot>
<template v-else>
<div :class="cx('content')" @click="onContentClick" @mousedown="onContentClick" @keydown="onContentKeydown" v-bind="ptm('content')">

View File

@ -1,5 +1,5 @@
<template>
<nav v-if="alwaysShow ? true : pageLinks && pageLinks.length > 1" v-bind="ptm('paginatorWrapper')">
<nav v-if="alwaysShow ? true : pageLinks && pageLinks.length > 1" v-bind="ptmi('paginatorWrapper')">
<div v-for="(value, key) in templateItems" :key="key" ref="paginator" :class="cx('paginator', { key })" v-bind="ptm('root')">
<div v-if="$slots.start" :class="cx('start')" v-bind="ptm('start')">
<slot name="start" :state="currentState"></slot>
@ -70,6 +70,7 @@ import RowsPerPageDropdown from './RowsPerPageDropdown.vue';
export default {
name: 'Paginator',
extends: BasePaginator,
inheritAttrs: false,
emits: ['update:first', 'update:rows', 'page'],
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<div :id="id" :class="cx('root')" v-bind="ptm('root')">
<div :id="id" :class="cx('root')" v-bind="ptmi('root')">
<template v-for="(item, index) of model" :key="getPanelKey(index)">
<div v-if="isItemVisible(item)" :style="getItemProp(item, 'style')" :class="[cx('panel'), getItemProp(item, 'class')]" v-bind="ptm('panel')">
<div
@ -63,6 +63,7 @@ import PanelMenuList from './PanelMenuList.vue';
export default {
name: 'PanelMenu',
extends: BasePanelMenu,
inheritAttrs: false,
emits: ['update:expandedKeys', 'panel-open', 'panel-close'],
data() {
return {

View File

@ -14,6 +14,7 @@
@blur="onBlur"
@keydown="onKeyDown"
@item-toggle="onItemToggle"
@item-mousemove="onItemMouseMove"
:pt="pt"
:unstyled="unstyled"
v-bind="ptm('menu')"
@ -225,6 +226,11 @@ export default {
this.focusedItem = processedItem;
DomHandler.focus(this.$el);
},
onItemMouseMove(event) {
if (this.focused) {
this.focusedItem = event.processedItem;
}
},
isElementInPanel(event, element) {
const panel = event.currentTarget.closest('[data-pc-section="panel"]');

View File

@ -16,14 +16,14 @@
:data-p-focused="isItemFocused(processedItem)"
:data-p-disabled="isItemDisabled(processedItem)"
>
<div :class="cx('content')" @click="onItemClick($event, processedItem)" v-bind="getPTOptions('content', processedItem, index)">
<div :class="cx('content')" @click="onItemClick($event, processedItem)" @mousemove="onItemMouseMove($event, processedItem)" v-bind="getPTOptions('content', processedItem, index)">
<template v-if="!templates.item">
<a v-ripple :href="getItemProp(processedItem, 'url')" :class="cx('action')" :target="getItemProp(processedItem, 'target')" tabindex="-1" aria-hidden="true" v-bind="getPTOptions('action', 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)" />
</template>
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" />
<component v-if="templates.itemicon" :is="templates.itemicon" :item="processedItem.item" :class="cx('icon')" />
<span v-else-if="getItemProp(processedItem, 'icon')" :class="[cx('icon'), getItemProp(processedItem, 'icon')]" v-bind="getPTOptions('icon', processedItem, index)" />
<span :class="cx('label')" v-bind="getPTOptions('label', processedItem, index)">{{ getItemLabel(processedItem) }}</span>
</a>
@ -52,6 +52,7 @@
:templates="templates"
:activeItemPath="activeItemPath"
@item-toggle="onItemToggle"
@item-mousemove="$emit('item-mousemove', $event)"
:pt="pt"
:unstyled="unstyled"
v-bind="ptm('submenu')"
@ -82,7 +83,7 @@ export default {
name: 'PanelMenuSub',
hostName: 'PanelMenu',
extends: BaseComponent,
emits: ['item-toggle'],
emits: ['item-toggle', 'item-mousemove'],
props: {
panelId: {
type: String,
@ -159,6 +160,9 @@ export default {
onItemToggle(event) {
this.$emit('item-toggle', event);
},
onItemMouseMove(event, processedItem) {
this.$emit('item-mousemove', { originalEvent: event, processedItem });
},
getAriaSetSize() {
return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length;
},

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" :style="sx('root')" v-bind="ptm('root')">
<div :class="cx('root')" :style="sx('root')" v-bind="ptmi('root')">
<PInputText
ref="input"
:id="inputId"
@ -27,10 +27,10 @@
:unstyled="unstyled"
/>
<slot v-if="toggleMask && unmasked" name="hideicon" :onClick="onMaskToggle" :toggleCallback="onMaskToggle">
<component :is="hideIcon ? 'i' : 'EyeSlashIcon'" :class="hideIcon" @click="onMaskToggle" v-bind="ptm('hideIcon')" />
<component :is="hideIcon ? 'i' : 'EyeSlashIcon'" :class="[cx('hideIcon'), hideIcon]" @click="onMaskToggle" v-bind="ptm('hideIcon')" />
</slot>
<slot v-if="toggleMask && !unmasked" name="showicon" :onClick="onMaskToggle" :toggleCallback="onMaskToggle">
<component :is="showIcon ? 'i' : 'EyeIcon'" :class="showIcon" @click="onMaskToggle" v-bind="ptm('showIcon')" />
<component :is="showIcon ? 'i' : 'EyeIcon'" :class="[cx('showIcon'), showIcon]" @click="onMaskToggle" v-bind="ptm('showIcon')" />
</slot>
<span class="p-hidden-accessible" aria-live="polite" v-bind="ptm('hiddenAccesible')" :data-p-hidden-accessible="true">
{{ infoText }}
@ -64,6 +64,7 @@ import BasePassword from './BasePassword.vue';
export default {
name: 'Password',
extends: BasePassword,
inheritAttrs: false,
emits: ['update:modelValue', 'change', 'focus', 'blur', 'invalid'],
data() {
return {

View File

@ -10,7 +10,7 @@ const classes = {
{
'p-inputwrapper-filled': instance.filled,
'p-inputwrapper-focus': instance.focused,
'p-input-icon-right': props.toggleMask
'p-icon-field p-icon-field-right': props.toggleMask
}
],
input: ({ props }) => [
@ -19,7 +19,9 @@ const classes = {
'p-disabled': props.disabled
}
],
panel: ({ props, instance }) => [
hideIcon: 'p-input-icon',
showIcon: 'p-input-icon',
panel: ({ instance }) => [
'p-password-panel p-component',
{
'p-ripple-disabled': instance.$primevue.config.ripple === false

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<div v-if="showSourceControls" :class="cx('sourceControls')" v-bind="ptm('sourceControls')" data-pc-group-section="controls">
<slot name="sourcecontrolsstart"></slot>
<PLButton :aria-label="moveUpAriaLabel" :disabled="moveDisabled(0)" type="button" @click="moveUp($event, 0)" v-bind="moveUpButtonProps" :pt="ptm('sourceMoveUpButton')" :unstyled="unstyled">
@ -201,6 +201,7 @@ import BasePickList from './BasePickList.vue';
export default {
name: 'PickList',
extends: BasePickList,
inheritAttrs: false,
emits: ['update:modelValue', 'reorder', 'update:selection', 'selection-change', 'move-to-target', 'move-to-source', 'move-all-to-target', 'move-all-to-source', 'focus', 'blur'],
itemTouched: false,
reorderDirection: null,

View File

@ -1,5 +1,5 @@
<template>
<div role="progressbar" :class="cx('root')" aria-valuemin="0" :aria-valuenow="value" aria-valuemax="100" v-bind="ptm('root')">
<div role="progressbar" :class="cx('root')" aria-valuemin="0" :aria-valuenow="value" aria-valuemax="100" v-bind="ptmi('root')">
<div v-if="determinate" :class="cx('value')" :style="progressStyle" v-bind="ptm('value')">
<div v-if="value != null && value !== 0 && showValue" :class="cx('label')" v-bind="ptm('label')">
<slot>{{ value + '%' }}</slot>
@ -17,6 +17,7 @@ import BaseProgressBar from './BaseProgressBar.vue';
export default {
name: 'ProgressBar',
extends: BaseProgressBar,
inheritAttrs: false,
computed: {
progressStyle() {
return {

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" role="progressbar" v-bind="ptm('root')">
<div :class="cx('root')" role="progressbar" v-bind="ptmi('root')">
<svg :class="cx('spinner')" viewBox="25 25 50 50" :style="svgStyle" v-bind="ptm('spinner')">
<circle :class="cx('circle')" cx="50" cy="50" r="20" :fill="fill" :stroke-width="strokeWidth" strokeMiterlimit="10" v-bind="ptm('circle')" />
</svg>
@ -12,6 +12,7 @@ import BaseProgressSpinner from './BaseProgressSpinner.vue';
export default {
name: 'ProgressSpinner',
extends: BaseProgressSpinner,
inheritAttrs: false,
computed: {
svgStyle() {
return {

View File

@ -13,6 +13,7 @@
:readonly="readonly"
:aria-labelledby="ariaLabelledby"
:aria-label="ariaLabel"
:aria-invalid="invalid || undefined"
@focus="onFocus"
@blur="onBlur"
@change="onChange"
@ -31,10 +32,13 @@ import BaseRadioButton from './BaseRadioButton.vue';
export default {
name: 'RadioButton',
extends: BaseRadioButton,
inheritAttrs: false,
emits: ['update:modelValue', 'change', 'focus', 'blur'],
methods: {
getPTOptions(key) {
return this.ptm(key, {
const _ptm = key === 'root' ? this.ptmi : this.ptm;
return _ptm(key, {
context: {
checked: this.checked,
disabled: this.disabled

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<div v-if="cancel" :class="cx('cancelItem')" @click="onOptionClick($event, 0)" v-bind="getPTOptions('cancelItem', 0)" :data-p-focused="focusedOptionIndex === 0">
<span class="p-hidden-accessible" v-bind="ptm('hiddenCancelInputWrapper')" :data-p-hidden-accessible="true">
<input
@ -58,6 +58,7 @@ import BaseRating from './BaseRating.vue';
export default {
name: 'Rating',
extends: BaseRating,
inheritAttrs: false,
emits: ['update:modelValue', 'change', 'focus', 'blur'],
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<div :class="cx('wrapper')" v-bind="ptm('wrapper')">
<div ref="content" :id="contentId" :class="cx('content')" @scroll="onScroll" @mouseenter="moveBar" v-bind="ptm('content')">
<slot></slot>
@ -46,6 +46,7 @@ import BaseScrollPanel from './BaseScrollPanel.vue';
export default {
name: 'ScrollPanel',
extends: BaseScrollPanel,
inheritAttrs: false,
initialized: false,
documentResizeListener: null,
documentMouseMoveListener: null,

View File

@ -1,6 +1,6 @@
<template>
<transition name="p-scrolltop" appear @enter="onEnter" @after-leave="onAfterLeave" v-bind="ptm('transition')">
<button v-if="visible" :ref="containerRef" :class="cx('root')" @click="onClick" type="button" :aria-label="scrollTopAriaLabel" v-bind="ptm('root')">
<button v-if="visible" :ref="containerRef" :class="cx('root')" @click="onClick" type="button" :aria-label="scrollTopAriaLabel" v-bind="ptmi('root')">
<slot name="icon" :class="cx('icon')">
<component :is="icon ? 'span' : 'ChevronUpIcon'" :class="[cx('icon'), icon]" v-bind="ptm('icon')" />
</slot>
@ -16,6 +16,7 @@ import BaseScrollTop from './BaseScrollTop.vue';
export default {
name: 'ScrollTop',
extends: BaseScrollTop,
inheritAttrs: false,
scrollListener: null,
container: null,
data() {

View File

@ -1,10 +1,10 @@
<template>
<div ref="container" :class="cx('root')" role="group" :aria-labelledby="ariaLabelledby" v-bind="ptm('root')">
<div ref="container" :class="cx('root')" role="group" :aria-labelledby="ariaLabelledby" v-bind="ptmi('root')">
<div
v-for="(option, i) of options"
:key="getOptionRenderKey(option)"
v-ripple
:tabindex="i === focusedIndex ? '0' : '-1'"
:tabindex="findTabindex(option, i)"
:aria-label="getOptionLabel(option)"
:role="multiple ? 'checkbox' : 'radio'"
:aria-checked="isSelected(option)"
@ -33,6 +33,7 @@ import BaseSelectButton from './BaseSelectButton.vue';
export default {
name: 'SelectButton',
extends: BaseSelectButton,
inheritAttrs: false,
emits: ['update:modelValue', 'focus', 'blur', 'change'],
data() {
return {
@ -129,7 +130,7 @@ export default {
case 'ArrowDown':
case 'ArrowRight': {
this.changeTabIndexes(event, 'next');
this.onArrowRightKey(event.target);
event.preventDefault();
break;
}
@ -137,7 +138,7 @@ export default {
case 'ArrowUp':
case 'ArrowLeft': {
this.changeTabIndexes(event, 'prev');
this.onArrowLeftKey(event.target);
event.preventDefault();
break;
}
@ -147,23 +148,46 @@ export default {
break;
}
},
changeTabIndexes(event, direction) {
let firstTabableChild, index;
onArrowRightKey(target) {
const nextEl = this.findNextElement(target);
for (let i = 0; i <= this.$refs.container.children.length - 1; i++) {
if (this.$refs.container.children[i].getAttribute('tabindex') === '0') firstTabableChild = { elem: this.$refs.container.children[i], index: i };
if (nextEl) {
this.focusedIndex = ObjectUtils.findIndexInList(nextEl, this.findAllElements());
DomHandler.focus(nextEl);
}
},
onArrowLeftKey(target) {
const prevEl = this.findPrevElement(target);
if (prevEl) {
this.focusedIndex = ObjectUtils.findIndexInList(prevEl, this.findAllElements());
DomHandler.focus(prevEl);
}
},
findAllElements() {
return DomHandler.find(this.$refs.container, '[data-pc-section="button"]');
},
findNextElement(target) {
if (target.nextElementSibling) {
if (DomHandler.getAttribute(target.nextElementSibling, 'data-p-disabled')) {
return this.findNextElement(target.nextElementSibling);
}
return target.nextElementSibling;
}
if (direction === 'prev') {
if (firstTabableChild.index === 0) index = this.$refs.container.children.length - 1;
else index = firstTabableChild.index - 1;
} else {
if (firstTabableChild.index === this.$refs.container.children.length - 1) index = 0;
else index = firstTabableChild.index + 1;
return null;
},
findPrevElement(target) {
if (target.previousElementSibling) {
if (DomHandler.getAttribute(target.previousElementSibling, 'data-p-disabled')) {
return this.findPrevElement(target.previousElementSibling);
}
return target.previousElementSibling;
}
this.focusedIndex = index;
this.$refs.container.children[index].focus();
return null;
},
onFocus(event) {
this.$emit('focus', event);
@ -174,6 +198,9 @@ export default {
}
this.$emit('blur', event, option);
},
findTabindex(option, index) {
return this.disabled || this.isOptionDisabled(option) || index !== this.focusedIndex ? '-1' : '0';
}
},
computed: {

View File

@ -2,7 +2,7 @@ import BaseStyle from 'primevue/base/style';
const classes = {
root: ({ props }) => [
'p-selectbutton p-buttonset p-component',
'p-selectbutton p-button-group p-component',
{
'p-disabled': props.disabled,
'p-invalid': props.invalid

View File

@ -2,7 +2,7 @@
<Portal>
<div v-if="containerVisible" :ref="maskRef" @mousedown="onMaskClick" :class="cx('mask')" :style="sx('mask', true, { position })" v-bind="ptm('mask')">
<transition name="p-sidebar" @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 :class="cx('root')" role="complementary" :aria-modal="modal" v-bind="{ ...$attrs, ...ptm('root') }">
<div v-if="visible" :ref="containerRef" v-focustrap :class="cx('root')" role="complementary" :aria-modal="modal" v-bind="ptmi('root')">
<slot v-if="$slots.container" name="container" :onClose="hide" :closeCallback="hide"></slot>
<template v-else>
<div :ref="headerContainerRef" :class="cx('header')" v-bind="ptm('header')">

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" :style="[sx('root'), containerStyle]" aria-hidden="true" v-bind="ptm('root')"></div>
<div :class="cx('root')" :style="[sx('root'), containerStyle]" aria-hidden="true" v-bind="ptmi('root')"></div>
</template>
<script>
@ -8,6 +8,7 @@ import BaseSkeleton from './BaseSkeleton.vue';
export default {
name: 'Skeleton',
extends: BaseSkeleton,
inheritAttrs: false,
computed: {
containerStyle() {
if (this.size) return { width: this.size, height: this.size, borderRadius: this.borderRadius };

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" @click="onBarClick" v-bind="ptm('root')" :data-p-sliding="false">
<div :class="cx('root')" @click="onBarClick" v-bind="ptmi('root')" :data-p-sliding="false">
<span :class="cx('range')" :style="[sx('range'), rangeStyle]" v-bind="ptm('range')"></span>
<span
v-if="!range"
@ -68,6 +68,7 @@ import BaseSlider from './BaseSlider.vue';
export default {
name: 'Slider',
extends: BaseSlider,
inheritAttrs: false,
emits: ['update:modelValue', 'change', 'slideend'],
dragging: false,
handleIndex: null,

View File

@ -1,5 +1,5 @@
<template>
<div :ref="containerRef" :class="containerClass" :style="[style, sx('root')]" v-bind="ptm('root')">
<div :ref="containerRef" :class="containerClass" :style="[style, sx('root')]" v-bind="ptmi('root')">
<slot name="button" :onClick="onClick" :toggleCallback="onClick">
<SDButton
type="button"
@ -63,6 +63,7 @@ import BaseSpeedDial from './BaseSpeedDial.vue';
export default {
name: 'SpeedDial',
extends: BaseSpeedDial,
inheritAttrs: false,
emits: ['click', 'show', 'hide', 'focus', 'blur'],
documentClickListener: null,
container: null,

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" :style="sx('root')" :data-p-resizing="false" v-bind="ptm('root', getPTOptions())">
<div :class="cx('root')" :style="sx('root')" :data-p-resizing="false" v-bind="ptmi('root', getPTOptions())">
<template v-for="(panel, i) of panels" :key="i">
<component :is="panel" tabindex="-1"></component>
<div
@ -28,6 +28,7 @@ import BaseSplitter from './BaseSplitter.vue';
export default {
name: 'Splitter',
extends: BaseSplitter,
inheritAttrs: false,
emits: ['resizestart', 'resizeend', 'resize'],
dragging: false,
mouseMoveListener: null,

View File

@ -1,5 +1,5 @@
<template>
<div ref="container" :class="cx('root')" v-bind="ptm('root', getPTOptions)">
<div ref="container" :class="cx('root')" v-bind="ptmi('root', getPTOptions)">
<slot></slot>
</div>
</template>
@ -10,6 +10,7 @@ import BaseSplitterPanel from './BaseSplitterPanel.vue';
export default {
name: 'SplitterPanel',
extends: BaseSplitterPanel,
inheritAttrs: false,
computed: {
isNested() {
return this.$slots.default().some((child) => {

View File

@ -0,0 +1,29 @@
<script>
import BaseComponent from 'primevue/basecomponent';
import StepperStyle from 'primevue/stepper/style';
export default {
name: 'BaseStepper',
extends: BaseComponent,
props: {
activeStep: {
type: Number,
default: 0
},
orientation: {
type: String,
default: 'horizontal'
},
linear: {
type: Boolean,
default: false
}
},
style: StepperStyle,
provide() {
return {
$parentInstance: this
};
}
};
</script>

191
components/lib/stepper/Stepper.d.ts vendored Normal file
View File

@ -0,0 +1,191 @@
/**
*
* Stepper is a component that streamlines a wizard-like workflow, organizing content into coherent steps and visually guiding users through a numbered progression in a multi-step process.
*
* [Live Demo](https://www.primevue.org/stepper/)
*
* @module stepper
*
*/
import { ComponentHooks } from '../basecomponent';
import { PassThroughOptions } from '../passthrough';
import { StepperPanelPassThroughOptionType } from '../stepperpanel';
import { ClassComponent, GlobalComponentConstructor, PassThrough } from '../ts-helpers';
export declare type StepperPassThroughOptionType = StepperPassThroughAttributes | ((options: StepperPassThroughMethodOptions) => StepperPassThroughAttributes | string) | string | null | undefined;
/**
* Custom passthrough(pt) option method.
*/
export interface StepperPassThroughMethodOptions {
/**
* Defines instance.
*/
instance: any;
/**
* Defines valid properties.
*/
props: StepperProps;
/**
* Defines current inline state.
*/
state: StepperState;
/**
* Defines valid attributes.
*/
attrs: any;
/**
* Defines parent options.
*/
parent: any;
/**
* Defines passthrough(pt) options in global config.
*/
global: object | undefined;
}
/**
* Custom passthrough(pt) options.
* @see {@link StepperProps.pt}
*/
export interface StepperPassThroughOptions {
/**
* Used to pass attributes to the root's DOM element.
*/
root?: StepperPassThroughOptionType;
/**
* Used to pass attributes to the nav container's DOM element.
*/
navContainer?: StepperPassThroughOptionType;
/**
* Used to pass attributes to the nav's DOM element.
*/
nav?: StepperPassThroughOptionType;
/**
* Used to pass attributes to the panel container's DOM element.
*/
panelContainer?: StepperPassThroughOptionType;
/**
* Used to pass attributes to the end handler's DOM element.
*/
stepperpanel?: StepperPanelPassThroughOptionType;
/**
* Used to manage all lifecycle hooks.
* @see {@link BaseComponent.ComponentHooks}
*/
hooks?: ComponentHooks;
}
/**
* Custom passthrough attributes for each DOM elements
*/
export interface StepperPassThroughAttributes {
[key: string]: any;
}
/**
* Defines current inline state in Stepper component.
*/
export interface StepperState {
/**
* Current active index state.
*/
d_activeStep: number;
/**
* Unique id for the Stepper component.
*/
id: string;
}
/**
* Custom tab change event.
* @see {@link StepperEmits['step-change']}
*/
export interface StepperChangeEvent {
/**
* Browser event
*/
originalEvent: Event;
/**
* Index of the selected stepper panel
*/
index: number;
}
/**
* Defines valid properties in Stepper component.
*/
export interface StepperProps {
/**
* Active step index of stepper.
* @defaultValue 0
*/
activeStep?: number | undefined;
/**
* Orientation of the stepper.
* @defaultValue horizontal
*/
orientation?: 'horizontal' | 'vertical' | undefined;
/**
* Whether the steps are clickable or not.
* @defaultValue false
*/
linear?: boolean | undefined;
/**
* Used to pass attributes to DOM elements inside the component.
* @type {StepperPassThroughOptions}
*/
pt?: PassThrough<StepperPassThroughOptions>;
/**
* Used to configure passthrough(pt) options of the component.
* @type {PassThroughOptions}
*/
ptOptions?: PassThroughOptions;
/**
* When enabled, it removes component related styles in the core.
* @defaultValue false
*/
unstyled?: boolean;
}
/**
* Defines valid slots in Stepper component.
*/
export interface StepperSlots {}
/**
* Defines valid emits in Stepper component.
*/
export interface StepperEmits {
/**
* Emitted when the value changes.
* @param {number | number[]} value - New value.
*/
'update:activeStep'(value: number): void;
/**
* Callback to invoke when an active panel is changed.
*/
'step-change'(event: StepperChangeEvent): void;
}
/**
* **PrimeVue - Stepper**
*
* _Stepper is a component that streamlines a wizard-like workflow, organizing content into coherent steps and visually guiding users through a numbered progression in a multi-step process._
*
* [Live Demo](https://www.primevue.org/stepper/)
* --- ---
* ![PrimeVue](https://primefaces.org/cdn/primevue/images/logo-100.png)
*
* @group Component
*
*/
declare class Stepper extends ClassComponent<StepperProps, StepperSlots, StepperEmits> {}
declare module '@vue/runtime-core' {
interface GlobalComponents {
Stepper: GlobalComponentConstructor<Stepper>;
}
}
export default Stepper;

View File

@ -0,0 +1,269 @@
<template>
<div :class="cx('root')" role="tablist" v-bind="ptmi('root')">
<slot v-if="$slots.start" name="start" />
<template v-if="orientation === 'horizontal'">
<div :class="cx('navContainer')" v-bind="ptm('navContainer')">
<ul ref="nav" :class="cx('nav')" v-bind="ptm('nav')">
<li
v-for="(step, index) of stepperpanels"
:key="getStepKey(step, index)"
:class="cx('stepper.header', { step, index })"
:aria-current="isStepActive(index) ? 'step' : undefined"
role="presentation"
v-bind="{ ...getStepPT(step, 'root', index), ...getStepPT(step, 'header', index) }"
data-pc-name="stepperpanel"
:data-p-highlight="isStepActive(index)"
:data-p-disabled="isItemDisabled(index)"
:data-pc-index="index"
:data-p-active="isStepActive(index)"
>
<slot name="header">
<StepperHeader
:id="getStepHeaderActionId(index)"
:template="step.children?.header"
:stepperpanel="step"
:index="index"
:disabled="isItemDisabled(index)"
:active="isStepActive(index)"
:highlighted="index < d_activeStep"
:class="cx('stepper.action')"
:aria-controls="getStepContentId(index)"
:clickCallback="(event) => onItemClick(event, index)"
:getStepPT="getStepPT"
:getStepProp="getStepProp"
/>
</slot>
<slot v-if="index !== stepperpanels.length - 1" name="separator">
<StepperSeparator
v-if="index !== stepperpanels.length - 1"
:template="step.children?.separator"
:separatorClass="cx('stepper.separator')"
:stepperpanel="step"
:index="index"
:active="isStepActive(index)"
:highlighted="index < d_activeStep"
:getStepPT="getStepPT(step, 'separator', index)"
/>
</slot>
</li>
</ul>
</div>
<div :class="cx('panelContainer')" v-bind="ptm('panelContainer')">
<template v-for="(step, index) of stepperpanels" :key="getStepKey(step, index)">
<StepperContent
v-if="isStepActive(index)"
:id="getStepContentId(index)"
:template="step?.children?.content"
:stepperpanel="step"
:index="index"
:active="isStepActive(index)"
:highlighted="index < d_activeStep"
:clickCallback="(event) => onItemClick(event, index)"
:prevCallback="(event) => prevCallback(event, index)"
:nextCallback="(event) => nextCallback(event, index)"
:getStepPT="getStepPT"
:aria-labelledby="getStepHeaderActionId(index)"
/>
</template>
</div>
</template>
<template v-else-if="orientation === 'vertical'">
<div
v-for="(step, index) of stepperpanels"
ref="nav"
:key="getStepKey(step, index)"
:class="cx('panel', { step, index })"
:aria-current="isStepActive(index) ? 'step' : undefined"
v-bind="{ ...getStepPT(step, 'root', index), ...getStepPT(step, 'panel', index) }"
data-pc-name="stepperpanel"
:data-p-highlight="isStepActive(index)"
:data-p-disabled="isItemDisabled(index)"
:data-pc-index="index"
:data-p-active="isStepActive(index)"
>
<div :class="cx('stepper.header', { step, index })" v-bind="getStepPT(step, 'header', index)">
<slot name="header">
<StepperHeader
:id="getStepHeaderActionId(index)"
:template="step.children?.header"
:stepperpanel="step"
:index="index"
:disabled="isItemDisabled(index)"
:active="isStepActive(index)"
:highlighted="index < d_activeStep"
:class="cx('stepper.action')"
:aria-controls="getStepContentId(index)"
:clickCallback="(event) => onItemClick(event, index)"
:getStepPT="getStepPT"
:getStepProp="getStepProp"
/>
</slot>
</div>
<div :class="cx('stepper.toggleableContent')" v-bind="getStepPT(step, 'toggleableContent', index)">
<slot v-if="index !== stepperpanels.length - 1" name="separator">
<StepperSeparator
v-if="index !== stepperpanels.length - 1"
:template="step.children?.separator"
:separatorClass="cx('stepper.separator')"
:stepperpanel="step"
:index="index"
:active="isStepActive(index)"
:highlighted="index < d_activeStep"
:getStepPT="getStepPT(step, 'separator', index)"
/>
</slot>
<transition name="p-toggleable-content" v-bind="getStepPT(step, 'transition', index)">
<slot name="content">
<StepperContent
v-show="isStepActive(index)"
:id="getStepContentId(index)"
:template="step?.children?.content"
:stepperpanel="step"
:index="index"
:active="isStepActive(index)"
:highlighted="index < d_activeStep"
:clickCallback="(event) => onItemClick(event, index)"
:prevCallback="(event) => prevCallback(event, index)"
:nextCallback="(event) => nextCallback(event, index)"
:getStepPT="getStepPT"
:aria-labelledby="getStepHeaderActionId(index)"
/>
</slot>
</transition>
</div>
</div>
</template>
<slot v-if="$slots.end" name="end" />
</div>
</template>
<script>
import { UniqueComponentId } from 'primevue/utils';
import { mergeProps } from 'vue';
import BaseStepper from './BaseStepper.vue';
import StepperContent from './StepperContent.vue';
import StepperHeader from './StepperHeader.vue';
import StepperSeparator from './StepperSeparator.vue';
export default {
name: 'Stepper',
extends: BaseStepper,
nheritAttrs: false,
emits: ['update:activeStep', 'step-change'],
data() {
return {
id: this.$attrs.id,
d_activeStep: this.activeStep
};
},
watch: {
'$attrs.id': function (newValue) {
this.id = newValue || UniqueComponentId();
},
activeStep(newValue) {
this.d_activeStep = newValue;
}
},
mounted() {
this.id = this.id || UniqueComponentId();
},
methods: {
isStep(child) {
return child.type.name === 'StepperPanel';
},
isStepActive(index) {
return this.d_activeStep === index;
},
getStepProp(step, name) {
return step.props ? step.props[name] : undefined;
},
getStepKey(step, index) {
return this.getStepProp(step, 'header') || index;
},
getStepHeaderActionId(index) {
return `${this.id}_${index}_header_action`;
},
getStepContentId(index) {
return `${this.id}_${index}_content`;
},
getStepPT(step, key, index) {
const count = this.stepperpanels.length;
const stepMetaData = {
props: step.props,
parent: {
instance: this,
props: this.$props,
state: this.$data
},
context: {
index,
count,
first: index === 0,
last: index === count - 1,
active: this.isStepActive(index),
highlighted: index < this.d_activeStep,
disabled: this.isItemDisabled(index)
}
};
return mergeProps(this.ptm(`stepperpanel.${key}`, { stepperpanel: stepMetaData }), this.ptm(`stepperpanel.${key}`, stepMetaData), this.ptmo(this.getStepProp(step, 'pt'), key, stepMetaData));
},
updateActiveStep(event, index) {
this.d_activeStep = index;
this.$emit('update:activeStep', index);
this.$emit('step-change', {
originalEvent: event,
index
});
},
onItemClick(event, index) {
if (this.linear) {
event.preventDefault();
return;
}
if (index !== this.d_activeStep) {
this.updateActiveStep(event, index);
}
},
isItemDisabled(index) {
return this.linear && !this.isStepActive(index);
},
prevCallback(event, index) {
if (index !== 0) {
this.onItemClick(event, index - 1);
}
},
nextCallback(event, index) {
if (index !== this.stepperpanels.length - 1) {
this.onItemClick(event, index + 1);
}
}
},
computed: {
stepperpanels() {
return this.$slots.default().reduce((stepperpanels, child) => {
if (this.isStep(child)) {
stepperpanels.push(child);
} else if (child.children && child.children instanceof Array) {
child.children.forEach((nestedChild) => {
if (this.isStep(nestedChild)) {
stepperpanels.push(nestedChild);
}
});
}
return stepperpanels;
}, []);
}
},
components: {
StepperContent,
StepperHeader,
StepperSeparator
}
};
</script>

View File

@ -0,0 +1,47 @@
<template>
<div
:id="id"
:class="cx('stepper.content', { stepperpanel, index })"
role="tabpanel"
:aria-labelledby="ariaLabelledby"
v-bind="{ ...getStepPT(stepperpanel, 'root', index), ...getStepPT(stepperpanel, 'content', index) }"
data-pc-name="stepperpanel"
:data-pc-index="index"
:data-p-active="active"
>
<component
v-if="template"
:is="template"
:index="index"
:active="active"
:highlighted="highlighted"
:clickCallback="(event) => onItemClick(event, index)"
:prevCallback="(event) => prevCallback(event, index)"
:nextCallback="(event) => nextCallback(event, index)"
></component>
<component v-else :is="stepperpanel"></component>
</div>
</template>
<script>
import BaseComponent from 'primevue/basecomponent';
export default {
name: 'StepperContent',
hostName: 'Stepper',
extends: BaseComponent,
props: {
id: null,
template: null,
ariaLabelledby: null,
stepperpanel: null,
index: null,
active: null,
highlighted: null,
clickCallback: null,
prevCallback: null,
nextCallback: null,
getStepPT: null
}
};
</script>

View File

@ -0,0 +1,30 @@
<template>
<component v-if="template" :is="template" :index="index" :active="active" :highlighted="highlighted" :class="cx('stepper.action')" :clickCallback="(event) => clickCallback(event, index)" />
<button v-else :id="id" :class="cx('stepper.action')" role="tab" :tabindex="disabled ? -1 : undefined" :aria-controls="ariaControls" @click="clickCallback($event, index)" v-bind="getStepPT(stepperpanel, 'action', index)">
<span :class="cx('stepper.number')" v-bind="getStepPT(stepperpanel, 'number', index)">{{ index + 1 }}</span>
<span :class="cx('stepper.title')" v-bind="getStepPT(stepperpanel, 'title', index)">{{ getStepProp(stepperpanel, 'header') }}</span>
</button>
</template>
<script>
import BaseComponent from 'primevue/basecomponent';
export default {
name: 'StepperHeader',
hostName: 'Stepper',
extends: BaseComponent,
props: {
id: null,
template: null,
stepperpanel: null,
index: null,
disabled: null,
active: null,
highlighted: null,
ariaControls: null,
clickCallback: null,
getStepPT: null,
getStepProp: null
}
};
</script>

View File

@ -0,0 +1,23 @@
<template>
<component v-if="template" :is="template" :class="separatorClass" :index="index" :active="active" :highlighted="highlighted" />
<span v-else :class="separatorClass" aria-hidden="true" v-bind="getStepPT" />
</template>
<script>
import BaseComponent from 'primevue/basecomponent';
export default {
name: 'StepperSeparator',
hostName: 'Stepper',
extends: BaseComponent,
props: {
template: null,
separatorClass: null,
stepperpanel: null,
index: null,
active: null,
highlighted: null,
getStepPT: null
}
};
</script>

View File

@ -0,0 +1,9 @@
{
"main": "./stepper.cjs.js",
"module": "./stepper.esm.js",
"unpkg": "./stepper.min.js",
"types": "./Stepper.d.ts",
"browser": {
"./sfc": "./Stepper.vue"
}
}

View File

@ -0,0 +1,3 @@
import { BaseStyle } from '../../base/style';
export interface StepperStyle extends BaseStyle {}

View File

@ -0,0 +1,46 @@
import BaseStyle from 'primevue/base/style';
const classes = {
root: ({ props }) => [
'p-stepper p-component',
{
'p-stepper-horizontal': props.orientation === 'horizontal',
'p-stepper-vertical': props.orientation === 'vertical',
'p-readonly': props.linear
}
],
navContainer: 'p-stepper-nav-container',
nav: 'p-stepper-nav',
stepper: {
header: ({ instance, step, index }) => [
'p-stepper-header',
{
'p-highlight': instance.isStepActive(index),
'p-disabled': instance.isItemDisabled(step, index)
}
],
action: 'p-stepper-action',
number: 'p-stepper-number',
title: 'p-stepper-title',
separator: 'p-stepper-separator',
toggleableContent: 'p-stepper-toggleable-content',
content: ({ props }) => [
'p-stepper-content',
{
'p-toggleable-content': props.orientation === 'vertical'
}
]
},
panelContainer: 'p-stepper-panels',
panel: ({ instance, props, index }) => [
'p-stepper-panel',
{
'p-stepper-panel-active': props.orientation === 'vertical' && instance.isStepActive(index)
}
]
};
export default BaseStyle.extend({
name: 'stepper',
classes
});

View File

@ -0,0 +1,6 @@
{
"main": "./stepperpanel.cjs.js",
"module": "./stepperpanel.esm.js",
"unpkg": "./stepperpanel.min.js",
"types": "./StepperPanel.d.ts"
}

View File

@ -0,0 +1,18 @@
<script>
import BaseComponent from 'primevue/basecomponent';
import StepperPanelStyle from 'primevue/stepperpanel/style';
export default {
name: 'BaseStepperPanel',
extends: BaseComponent,
props: {
header: null
},
style: StepperPanelStyle,
provide() {
return {
$parentInstance: this
};
}
};
</script>

View File

@ -0,0 +1,274 @@
/**
*
* StepperPanel is a helper component for StepperPanel component.
*
* [Live Demo](https://www.primevue.org/stepper/)
*
* @module stepperpanel
*
*/
import { TransitionProps, VNode } from 'vue';
import { ComponentHooks } from '../basecomponent';
import { PassThroughOptions } from '../passthrough';
import { ClassComponent, GlobalComponentConstructor, PassThrough } from '../ts-helpers';
export declare type StepperPanelPassThroughOptionType = StepperPanelPassThroughAttributes | ((options: StepperPanelPassThroughMethodOptions) => StepperPanelPassThroughAttributes | string) | string | null | undefined;
export declare type StepperPanelPassThroughTransitionType = TransitionProps | ((options: StepperPanelPassThroughMethodOptions) => TransitionProps) | undefined;
/**
* Custom passthrough(pt) option method.
*/
export interface StepperPanelPassThroughMethodOptions {
/**
* Defines instance.
*/
instance: any;
/**
* Defines valid properties.
*/
props: StepperPanelProps;
/**
* Defines current options.
*/
context: StepperPanelContext;
/**
* Defines valid attributes.
*/
attrs: any;
/**
* Defines parent options.
*/
parent: any;
/**
* Defines passthrough(pt) options in global config.
*/
global: object | undefined;
}
/**
* Custom passthrough(pt) options.
* @see {@link StepperPanelProps.pt}
*/
export interface StepperPanelPassThroughOptions {
/**
* Used to pass attributes to the root's DOM element.
*/
root?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the header's DOM element.
*/
header?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the action's DOM element.
*/
action?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the number's DOM element.
*/
number?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the title's DOM element.
*/
title?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the separator's DOM element.
*/
separator?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the content's DOM element.
*/
content?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the panel's DOM element.
*/
panel?: StepperPanelPassThroughOptionType;
/**
* Used to pass attributes to the toggleable content's DOM element.
*/
toggleableContent?: StepperPanelPassThroughOptionType;
/**
* Used to control Vue Transition API.
*/
transition?: StepperPanelPassThroughTransitionType;
/**
* Used to manage all lifecycle hooks.
* @see {@link BaseComponent.ComponentHooks}
*/
hooks?: ComponentHooks;
}
export interface StepperPanelPassThroughAttributes {
[key: string]: any;
}
/**
* Defines valid properties in StepperPanel component.
*/
export interface StepperPanelProps {
/**
* Orientation of tab headers.
*/
header?: string | undefined;
/**
* Used to pass attributes to DOM elements inside the component.
* @type {StepperPanelPassThroughOptions}
*/
pt?: PassThrough<StepperPanelPassThroughOptions>;
/**
* Used to configure passthrough(pt) options of the component.
* @type {PassThroughOptions}
*/
ptOptions?: PassThroughOptions;
}
/**
* Defines current options in StepperPanel component.
*/
export interface StepperPanelContext {
/**
* Current index of the stepperpanel.
*/
index: number;
/**
* Count of stepperpanels
*/
count: number;
/**
* Whether the stepperpanel is first.
*/
first: boolean;
/**
* Whether the stepperpanel is last.
*/
last: boolean;
/**
* Whether the stepperpanel is active.
*/
active: boolean;
/**
* Whether the stepperpanel is highlighted.
*/
highlighted: boolean;
/**
* Whether the stepperpanel is disabled.
*/
disabled: boolean;
}
/**
* Defines valid slots in StepperPanel slots.
*/
export interface StepperPanelSlots {
/**
* Custom content template.
*/
default(): VNode[];
/**
* Custom header template.
*/
header(scope: {
/**
* Index of the stepperpanel
*/
index: number;
/**
* Current active state of the stepperpanel
*/
active: boolean;
/**
* Current highlighted state of the stepperpanel
*/
highlighted: boolean;
/**
* Style class of the stepperpanel
*/
class: string;
/**
* Header click function.
* @param {Event} event - Browser event
*/
clickCallback: (event: Event) => void;
}): VNode[];
/**
* Custom content template.
*/
content(scope: {
/**
* Index of the stepperpanel
*/
index: number;
/**
* Current active state of the stepperpanel
*/
active: boolean;
/**
* Current highlighted state of the stepperpanel
*/
highlighted: boolean;
/**
* Style class of the stepperpanel
*/
class: string;
/**
* Content click function.
* @param {Event} event - Browser event
*/
clickCallback: (event: Event) => void;
/**
* Content previous panel click function.
* @param {Event} event - Browser event
*/
prevCallback: (event: Event) => void;
/**
* Content next panel click function.
* @param {Event} event - Browser event
*/
nextCallback: (event: Event) => void;
}): VNode[];
/**
* Custom separator template.
*/
separator(scope: {
/**
* Index of the stepperpanel
*/
index: number;
/**
* Current active state of the stepperpanel
*/
active: boolean;
/**
* Current highlighted state of the stepperpanel
*/
highlighted: boolean;
/**
* Style class of the stepperpanel
*/
class: string;
}): VNode[];
}
export interface StepperPanelEmits {}
/**
* **PrimeVue - StepperPanel**
*
* _StepperPanel is a helper component for Stepper component._
*
* [Live Demo](https://www.primevue.org/stepper/)
* --- ---
* ![PrimeVue](https://primefaces.org/cdn/primevue/images/logo-100.png)
*
* @group Component
*
*/
declare class StepperPanel extends ClassComponent<StepperPanelProps, StepperPanelSlots, StepperPanelEmits> {}
declare module '@vue/runtime-core' {
interface GlobalComponents {
StepperPanel: GlobalComponentConstructor<StepperPanel>;
}
}
export default StepperPanel;

View File

@ -0,0 +1,12 @@
<template>
<slot />
</template>
<script>
import BaseStepperPanel from './BaseStepperPanel.vue';
export default {
name: 'StepperPanel',
extends: BaseStepperPanel
};
</script>

View File

@ -0,0 +1,9 @@
{
"main": "./stepperpanel.cjs.js",
"module": "./stepperpanel.esm.js",
"unpkg": "./stepperpanel.min.js",
"types": "./StepperPanel.d.ts",
"browser": {
"./sfc": "./StepperPanel.vue"
}
}

View File

@ -0,0 +1,3 @@
import { BaseStyle } from '../../base/style';
export interface StepperPanelStyle extends BaseStyle {}

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1,6 @@
{
"main": "./stepperpanelstyle.cjs.js",
"module": "./stepperpanelstyle.esm.js",
"unpkg": "./stepperpanelstyle.min.js",
"types": "./StepperPanelStyle.d.ts"
}

View File

@ -1,5 +1,5 @@
<template>
<nav :id="id" :class="cx('root')" v-bind="ptm('root')">
<nav :id="id" :class="cx('root')" v-bind="ptmi('root')">
<ol ref="list" :class="cx('menu')" v-bind="ptm('menu')">
<template v-for="(item, index) of model" :key="label(item) + '_' + index.toString()">
<li
@ -34,6 +34,7 @@ import BaseSteps from './BaseSteps.vue';
export default {
name: 'Steps',
extends: BaseSteps,
inheritAttrs: false,
emits: ['update:activeStep', 'step-change'],
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" v-bind="ptm('root')">
<div :class="cx('root')" v-bind="ptmi('root')">
<ul ref="nav" :class="cx('menu')" role="menubar" :aria-labelledby="ariaLabelledby" :aria-label="ariaLabel" v-bind="ptm('menu')">
<template v-for="(item, i) of model" :key="label(item) + '_' + i.toString()">
<li
@ -15,7 +15,7 @@
>
<template v-if="!$slots.item">
<a ref="tabLink" v-ripple role="menuitem" :href="item.url" :class="cx('action')" :target="item.target" :aria-label="label(item)" :aria-disabled="disabled(item)" :tabindex="-1" v-bind="getPTOptions('action', item, i)">
<component v-if="$slots.itemicon" :is="$slots.itemicon" :item="item" :class="[cx('icon'), item.icon]" />
<component v-if="$slots.itemicon" :is="$slots.itemicon" :item="item" :class="cx('icon')" />
<span v-else-if="item.icon" :class="[cx('icon'), item.icon]" v-bind="getPTOptions('icon', item, i)" />
<span :class="cx('label')" v-bind="getPTOptions('label', item, i)">{{ label(item) }}</span>
</a>
@ -37,6 +37,7 @@ import BaseTabMenu from './BaseTabMenu.vue';
export default {
name: 'TabMenu',
extends: BaseTabMenu,
inheritAttrs: false,
emits: ['update:activeIndex', 'tab-change'],
timeout: null,
data() {

View File

@ -181,7 +181,7 @@ export interface TabPanelEmits {}
/**
* **PrimeVue - TabPanel**
*
* _TabPanel is a helper component for TabPanel component._
* _TabPanel is a helper component for TabView component._
*
* [Live Demo](https://www.primevue.org/tabview/)
* --- ---

View File

@ -13,7 +13,37 @@ import { PassThroughOptions } from '../passthrough';
import { TabPanelPassThroughOptionType } from '../tabpanel';
import { ClassComponent, GlobalComponentConstructor, PassThrough } from '../ts-helpers';
export declare type TabViewPassThroughOptionType = TabViewPassThroughAttributes | ((options: { props: TabViewProps; state: TabViewState }) => TabViewPassThroughAttributes | string) | string | null | undefined;
export declare type TabViewPassThroughOptionType = TabViewPassThroughAttributes | ((options: TabViewPassThroughMethodOptions) => TabViewPassThroughAttributes | string) | string | null | undefined;
/**
* Custom passthrough(pt) option method.
*/
export interface TabViewPassThroughMethodOptions {
/**
* Defines instance.
*/
instance: any;
/**
* Defines valid properties.
*/
props: TabViewProps;
/**
* Defines current inline state.
*/
state: TabViewState;
/**
* Defines valid attributes.
*/
attrs: any;
/**
* Defines parent options.
*/
parent: any;
/**
* Defines passthrough(pt) options in global config.
*/
global: object | undefined;
}
/**
* Custom tab change event.

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" role="tablist" v-bind="ptm('root')">
<div :class="cx('root')" role="tablist" v-bind="ptmi('root')">
<div :class="cx('navContainer')" v-bind="ptm('navContainer')">
<button
v-if="scrollable && !isPrevButtonDisabled"
@ -13,7 +13,7 @@
v-bind="{ ...previousButtonProps, ...ptm('previousButton') }"
data-pc-group-section="navbutton"
>
<slot name="previcon">
<slot name="previousicon">
<component :is="prevIcon ? 'span' : 'ChevronLeftIcon'" aria-hidden="true" :class="prevIcon" v-bind="ptm('previousIcon')" />
</slot>
</button>
@ -102,6 +102,7 @@ import BaseTabView from './BaseTabView.vue';
export default {
name: 'TabView',
extends: BaseTabView,
inheritAttrs: false,
emits: ['update:activeIndex', 'tab-change', 'tab-click'],
data() {
return {

View File

@ -1,5 +1,5 @@
<template>
<span :class="cx('root')" v-bind="ptm('root')">
<span :class="cx('root')" v-bind="ptmi('root')">
<component v-if="$slots.icon" :is="$slots.icon" :class="cx('icon')" v-bind="ptm('icon')" />
<span v-else-if="icon" :class="[cx('icon'), icon]" v-bind="ptm('icon')"></span>
<slot v-if="value || $slots.default">
@ -13,6 +13,7 @@ import BaseTag from './BaseTag.vue';
export default {
name: 'Tag',
extends: BaseTag
extends: BaseTag,
inheritAttrs: false
};
</script>

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" @click="onClick" v-bind="ptm('root')">
<div :class="cx('root')" @click="onClick" v-bind="ptmi('root')">
<div v-if="welcomeMessage" v-bind="ptm('welcomeMessage')">{{ welcomeMessage }}</div>
<div :class="cx('content')" v-bind="ptm('content')">
<div v-for="(command, i) of commands" :key="command.text + i.toString()" v-bind="ptm('commands')">
@ -22,6 +22,7 @@ import BaseTerminal from './BaseTerminal.vue';
export default {
name: 'Terminal',
extends: BaseTerminal,
inheritAttrs: false,
data() {
return {
commandText: null,

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