Implemented SelectButton

pull/7362/head
Cagatay Civici 2025-03-02 00:04:47 +03:00
parent fbce6895bb
commit e21ab4a480
12 changed files with 371 additions and 1 deletions

View File

@ -30,6 +30,10 @@
"name": "InputText",
"to": "/inputtext"
},
{
"name": "SelectButton",
"to": "/selectbutton"
},
{
"name": "Slider",
"to": "/slider"

View File

@ -0,0 +1,36 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
SelectButton is used with the <i>v-model</i> property for two-way value binding along with the <i>options</i> collection. Label and value of an option are defined with the <i>optionLabel</i> and <i>optionValue</i> properties respectively.
Note that, when options are simple primitive values such as a string array, no <i>optionLabel</i> and <i>optionValue</i> would be necessary.
</p>
</DocSectionText>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref('One Way');
const options = ref(['One-Way', 'Return']);
const code = ref(`
<template>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" />
</div>
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref('One Way');
const options = ref(['One-Way', 'Return']);
<\/script>
`);
</script>

View File

@ -0,0 +1,45 @@
<template>
<DocSectionText v-bind="$attrs">
<p>When <i>disabled</i> is present, the element cannot be edited and focused entirely. Certain options can also be disabled using the <i>optionDisabled</i> property.</p>
</DocSectionText>
<div class="card flex justify-center flex-wrap gap-4">
<SelectButton v-model="value1" :options="options1" disabled />
<SelectButton v-model="value2" :options="options2" optionDisabled="constant" optionLabel="name" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value1 = ref('One Way');
const value2 = ref('One Way');
const options1 = ref(['Off', 'On']);
const options2 = ref([
{ name: 'Option 1', value: 1, constant: false },
{ name: 'Option 2', value: 2, constant: true }
]);
const code = ref(`
<template>
<div class="card flex justify-center flex-wrap gap-4">
<SelectButton v-model="value1" :options="options1" disabled />
<SelectButton v-model="value2" :options="options2" optionDisabled="constant" optionLabel="name" />
</div>
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value1 = ref('One Way');
const value2 = ref('One Way');
const options1 = ref(['Off', 'On']);
const options2 = ref([
{ name: 'Option 1', value: 1, constant: false },
{ name: 'Option 2', value: 2, constant: true }
]);
<\/script>
`);
</script>

View File

@ -0,0 +1,16 @@
<template>
<DocSectionText v-bind="$attrs" />
<DocSectionCode :code="code" lang="script" />
</template>
<script>
export default {
data() {
return {
code: `
import SelectButton from '@/plex/selectbutton';
`
};
}
};
</script>

View File

@ -0,0 +1,33 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Invalid state is displayed using the <i>invalid</i> prop to indicate a failed validation. You can use this style when integrating with form validation libraries.</p>
</DocSectionText>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" aria-labelledby="basic" allowEmpty :invalid="value === null" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref(null);
const options = ref(['One-Way', 'Return']);
const code = ref(`
<template>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" aria-labelledby="basic" allowEmpty :invalid="value === null" />
</div>
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref(null);
const options = ref(['One-Way', 'Return']);
<\/script>
`);
</script>

View File

@ -0,0 +1,41 @@
<template>
<DocSectionText v-bind="$attrs">
<p>SelectButton allows selecting only one item by default and setting <i>multiple</i> option enables choosing more than one item. In multiple case, model property should be an array.</p>
</DocSectionText>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" optionLabel="name" multiple aria-labelledby="multiple" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref(null);
const options = ref([
{ name: 'Option 1', value: 1 },
{ name: 'Option 2', value: 2 },
{ name: 'Option 3', value: 3 }
]);
const code = ref(`
<template>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" optionLabel="name" multiple aria-labelledby="multiple" />
</div>
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref(null);
const options = ref([
{ name: 'Option 1', value: 1 },
{ name: 'Option 2', value: 2 },
{ name: 'Option 3', value: 3 }
]);
<\/script>
`);
</script>

View File

@ -0,0 +1,41 @@
<template>
<DocSectionText v-bind="$attrs">
<p>SelectButton provides <i>small</i> and <i>large</i> sizes as alternatives to the base.</p>
</DocSectionText>
<div class="card flex flex-col items-center gap-4">
<SelectButton v-model="value1" :options="options" size="small" />
<SelectButton v-model="value2" :options="options" />
<SelectButton v-model="value3" :options="options" size="large" />
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value1 = ref(null);
const value2 = ref('Beginner');
const value3 = ref('Expert');
const options = ref(['Beginner', 'Expert']);
const code = ref(`
<template>
<div class="card flex flex-col items-center gap-4">
<SelectButton v-model="value1" :options="options" size="small" />
<SelectButton v-model="value2" :options="options" />
<SelectButton v-model="value3" :options="options" size="large" />
</div>
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value1 = ref(null);
const value2 = ref('Beginner');
const value3 = ref('Expert');
const options = ref(['Beginner', 'Expert']);
<\/script>
`);
</script>

View File

@ -0,0 +1,51 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Label of an option is used as the display text of an item by default, for custom content support define an <i>option</i> template that gets the option instance as a parameter.</p>
</DocSectionText>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" optionLabel="value" dataKey="value" aria-labelledby="custom">
<template #option="slotProps">
<i :class="slotProps.option.icon"></i>
</template>
</SelectButton>
</div>
<DocSectionCode :code="code" />
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref(null);
const options = ref([
{ icon: 'pi pi-align-left', value: 'Left' },
{ icon: 'pi pi-align-right', value: 'Right' },
{ icon: 'pi pi-align-center', value: 'Center' },
{ icon: 'pi pi-align-justify', value: 'Justify' }
]);
const code = ref(`
<template>
<div class="card flex justify-center">
<SelectButton v-model="value" :options="options" optionLabel="value" dataKey="value" aria-labelledby="custom">
<template #option="slotProps">
<i :class="slotProps.option.icon"></i>
</template>
</SelectButton>
</div>
</template>
<script setup>
import SelectButton from '@/plex/selectbutton';
import { ref } from 'vue';
const value = ref(null);
const options = ref([
{ icon: 'pi pi-align-left', value: 'Left' },
{ icon: 'pi pi-align-right', value: 'Right' },
{ icon: 'pi pi-align-center', value: 'Center' },
{ icon: 'pi pi-align-justify', value: 'Justify' }
]);
<\/script>
`);
</script>

View File

@ -0,0 +1,57 @@
<template>
<DocComponent title="Vue SelectButton Component" header="SelectButton" description="SelectButton is used to choose single or multiple items from a list using buttons." :componentDocs="docs" :apiDocs="['SelectButton']" />
</template>
<script>
import BasicDoc from '@/doc/selectbutton/BasicDoc.vue';
import DisabledDoc from '@/doc/selectbutton/DisabledDoc.vue';
import ImportDoc from '@/doc/selectbutton/ImportDoc.vue';
import InvalidDoc from '@/doc/selectbutton/InvalidDoc.vue';
import MultipleDoc from '@/doc/selectbutton/MultipleDoc.vue';
import SizesDoc from '@/doc/selectbutton/SizesDoc.vue';
import TemplateDoc from '@/doc/selectbutton/TemplateDoc.vue';
export default {
data() {
return {
docs: [
{
id: 'import',
label: 'Import',
component: ImportDoc
},
{
id: 'basic',
label: 'Basic',
component: BasicDoc
},
{
id: 'multiple',
label: 'Multiple',
component: MultipleDoc
},
{
id: 'template',
label: 'Template',
component: TemplateDoc
},
{
id: 'sizes',
label: 'Sizes',
component: SizesDoc
},
{
id: 'invalid',
label: 'Invalid',
component: InvalidDoc
},
{
id: 'disabled',
label: 'Disabled',
component: DisabledDoc
}
]
};
}
};
</script>

View File

@ -0,0 +1,39 @@
<template>
<SelectButton unstyled :pt="theme">
<template v-for="(_, slotName) in $slots" v-slot:[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps ?? {}" />
</template>
</SelectButton>
</template>
<script setup>
import SelectButton from 'primevue/selectbutton';
import { ref } from 'vue';
const theme = ref({
root: `inline-flex select-none rounded-md
p-invalid:outline p-invalid:outline-offset-0 p-invalid:outline-red-400 dark:p-invalid:outline-red-300`,
pcToggleButton: {
root: `inline-flex items-center justify-center overflow-hidden relative cursor-pointer select-none
border border-surface-100 dark:border-surface-950
rounded-none first:rounded-s-md last:rounded-e-md
bg-surface-100 dark:bg-surface-950
text-surface-500 dark:text-surface-400
p-checked:text-surface-700 dark:p-checked:text-surface-0
text-base font-medium
focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary focus-visible:relative focus-visible:z-10
disabled:cursor-default
disabled:bg-surface-200 disabled:border-surface-200 disabled:text-surface-500
disabled:dark:bg-surface-700 disabled:dark:border-surface-700 disabled:dark:text-surface-400
p-invalid:border-red-400 dark:p-invalid:border-red-300
transition-colors duration-200
p-1 p-small:text-sm p-large:text-lg
`,
content: `relative flex-auto inline-flex items-center justify-center gap-2 py-1 px-3
rounded-md transition-colors duration-200
p-checked:bg-surface-0 dark:p-checked:bg-surface-800 p-checked:shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02),0px_1px_2px_0px_rgba(0,0,0,0.04)]`,
icon: ``,
label: ``
}
});
</script>

View File

@ -7,6 +7,7 @@
</template>
<script setup>
import ToggleButton from 'primevue/togglebutton';
import { ref } from 'vue';
const theme = ref({

View File

@ -1,5 +1,5 @@
<template>
<div :class="cx('root')" role="group" :aria-labelledby="ariaLabelledby" v-bind="ptmi('root')">
<div :class="cx('root')" role="group" :aria-labelledby="ariaLabelledby" v-bind="ptmi('root')" :data-p="dataP">
<template v-for="(option, index) of options" :key="getOptionRenderKey(option)">
<ToggleButton
:modelValue="isSelected(option)"
@ -23,6 +23,7 @@
</template>
<script>
import { cn } from '@primeuix/utils';
import { equals, resolveFieldData } from '@primeuix/utils/object';
import Ripple from 'primevue/ripple';
import ToggleButton from 'primevue/togglebutton';
@ -93,6 +94,11 @@ export default {
computed: {
equalityKey() {
return this.optionValue ? null : this.dataKey;
},
dataP() {
return cn({
invalid: this.$invalid
});
}
},
directives: {