import type { Meta, StoryObj } from '@storybook/vue3'
import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue'
import { ref, watch } from 'vue'
import { fn } from '@storybook/test'
import { getValidationDocumentation } from '@/composables/unifyValidation/documentationValidationProps'
const meta = {
title: 'Composants/Formulaires/SyCheckbox',
component: SyCheckbox,
decorators: [
() => ({
template: '
',
}),
],
parameters: {
layout: 'fullscreen',
controls: { exclude: ['modelValue', 'errorMessages', 'warningMessages', 'successMessages'] },
docs: {
description: {
component: `SyCheckbox est un composant de case à cocher tri-état qui étend le composant VCheckbox de Vuetify avec des fonctionnalités supplémentaires comme la validation personnalisée et l'état indéterminé.`,
},
},
},
argTypes: {
...getValidationDocumentation(),
modelValue: { control: 'boolean' },
label: {
description: 'Texte affiché comme label de la case à cocher',
control: 'text',
},
helpText: {
description: 'Texte d\'aide affiché sous la case (masqué quand un message de validation est présent)',
control: 'text',
},
color: {
control: 'select',
options: ['primary', 'success', 'error', 'warning'],
description: 'Couleur de la case à cocher',
},
indeterminate: {
description: 'État indéterminé de la case à cocher',
control: 'boolean',
},
disabled: {
description: 'Désactive la case à cocher',
control: 'boolean',
},
readonly: {
description: 'Rend la case à cocher en lecture seule',
control: 'boolean',
},
required: {
description: 'Rend la case à cocher obligatoire',
control: 'boolean',
},
hideDetails: {
description: 'Masque les détails (messages d\'erreur, etc.)',
control: 'boolean',
},
density: {
control: 'select',
options: ['default', 'comfortable', 'compact'],
description: 'Densité de la case à cocher',
},
customRules: {
description: 'Règles de validation personnalisées',
control: 'object',
},
customWarningRules: {
description: 'Règles d\'avertissement personnalisées',
control: 'object',
},
customSuccessRules: {
description: 'Règles de succès personnalisées',
control: 'object',
},
showSuccessMessages: {
description: 'Afficher les messages de succès',
control: 'boolean',
},
isValidateOnBlur: {
description: 'Vérifie la validité lors de la perte de focus',
control: 'boolean',
default: true,
},
disableErrorHandling: {
control: 'boolean',
description: 'Désactive complètement la validation des règles et l\'affichage des erreurs',
},
controlsIds: {
description: 'IDs des éléments contrôlés par cette case à cocher (pour l\'état indéterminé)',
control: 'object',
},
displayAsterisk: {
description: 'Afficher l\'astérisque (*) pour indiquer un champ obligatoire',
control: 'boolean',
},
},
} as Meta
export default meta
type Story = StoryObj
export const Default: Story = {
parameters: {
sourceCode: [
{
name: 'Template',
code: ``,
},
],
},
args: {
'onUpdate:modelValue': fn(),
'onUpdate:indeterminate': fn(),
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked = ref(false)
return { args, checked }
},
template: ``,
}),
}
export const Required: Story = {
args: {
...Default.args,
required: true,
isValidateOnBlur: false,
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked = ref(false)
return { args, checked }
},
template: ``,
}),
parameters: {
sourceCode: [
{
name: 'Template',
code: ``,
},
],
docs: {
description: {
story: `
### Case à cocher obligatoire
Cette case à cocher est marquée comme obligatoire, ce qui déclenchera une validation si elle n'est pas cochée.
`,
},
},
},
}
export const Indeterminate: Story = {
args: {
...Default.args,
indeterminate: true,
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked = ref(false)
const indeterminate = ref(true)
return { args, checked, indeterminate }
},
template: ``,
}),
parameters: {
sourceCode: [
{
name: 'Template',
code: `
`,
},
],
docs: {
description: {
story: `
### Case à cocher avec état indéterminé
Cette case à cocher est dans un état indéterminé, généralement utilisé lorsque certains éléments d'un groupe sont sélectionnés mais pas tous.
`,
},
},
},
}
export const HelpText: Story = {
args: {
...Default.args,
helpText: 'Cochez cette case pour accepter les conditions générales.',
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked = ref(false)
return { args, checked }
},
template: ``,
}),
parameters: {
sourceCode: [
{
name: 'Template',
code: ``,
},
],
docs: {
description: {
story: `
### Case à cocher avec texte d'aide
Un texte d'aide (\`helpText\`) s'affiche sous la case pour guider l'utilisateur, tant qu'aucun message de validation (erreur, avertissement, succès) n'est présent.
`,
},
},
},
}
export const WithControlsIds: Story = {
parameters: {
sourceCode: [
{
name: 'Template',
code: `
`,
},
{
name: 'Script',
code: `
`,
},
],
docs: {
description: {
story: `
### Case à cocher avec contrôle d'éléments enfants
Cette case à cocher contrôle un groupe d'éléments enfants. Elle utilise la propriété \`controlsIds\` pour établir la relation entre le parent et les enfants.
Lorsque certains enfants sont cochés mais pas tous, le parent passe automatiquement en état indéterminé.
La propriété \`controlsIds\` permet de créer une relation sémantique entre une case à cocher parent et ses enfants, ce qui est important pour l'accessibilité. Cette relation est établie via les attributs \`aria-controls\` et les identifiants des cases à cocher enfants.
`,
},
},
},
render: args => ({
components: { SyCheckbox },
setup() {
const parentChecked = ref(false)
const parentIndeterminate = ref(false)
const childChecked1 = ref(false)
const childChecked2 = ref(false)
const childChecked3 = ref(false)
// Logique pour gérer l'état indéterminé du parent
function updateParentState() {
const checkedCount = [
childChecked1.value,
childChecked2.value,
childChecked3.value,
].filter(Boolean).length
if (checkedCount === 0) {
parentChecked.value = false
parentIndeterminate.value = false
}
else if (checkedCount === 3) {
parentChecked.value = true
parentIndeterminate.value = false
}
else {
parentChecked.value = false
parentIndeterminate.value = true
}
}
// Observer les changements des enfants
const watchChild = () => {
updateParentState()
}
// Mettre à jour les enfants lorsque le parent change
const watchParent = () => {
if (!parentIndeterminate.value) {
childChecked1.value = parentChecked.value
childChecked2.value = parentChecked.value
childChecked3.value = parentChecked.value
}
}
// Configurer les observateurs
watch(childChecked1, watchChild)
watch(childChecked2, watchChild)
watch(childChecked3, watchChild)
watch(parentChecked, watchParent)
return {
args,
parentChecked,
parentIndeterminate,
childChecked1,
childChecked2,
childChecked3,
}
},
template: `
`,
}),
}
export const ValidationRules: Story = {
parameters: {
sourceCode: [
{
name: 'Template',
code: `
`,
},
{
name: 'Script',
code: `
// Composition API
export default {
setup() {
const checked = ref(false)
const rules = [
{
type: 'custom',
options: {
message: 'Cette case doit être cochée pour continuer.',
validate: (value) => value === true,
},
},
]
return {
checked,
rules,
}
}
}`,
},
],
docs: {
description: {
story: `
### Case à cocher avec règles de validation personnalisées
Cette case à cocher utilise des règles de validation personnalisées pour vérifier si elle est cochée.
`,
},
},
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked = ref(false)
return {
args,
checked,
rules: [
{
type: 'custom',
options: {
message: 'Cette case doit être cochée pour continuer.',
validate: (value: boolean) => value === true,
},
},
],
isValidateOnBlur: false,
}
},
template: `
`,
}),
}
export const DisabledState: Story = {
args: {
...Default.args,
disabled: true,
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked = ref(true)
return { args, checked }
},
template: ``,
}),
parameters: {
sourceCode: [
{
name: 'Template',
code: ``,
},
],
docs: {
description: {
story: `
### Case à cocher désactivée
Cette case à cocher est désactivée et ne peut pas être modifiée par l'utilisateur.
`,
},
},
},
}
export const ReadonlyState: Story = {
args: {
...Default.args,
readonly: true,
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked = ref(true)
return { args, checked }
},
template: ``,
}),
parameters: {
sourceCode: [
{
name: 'Template',
code: ``,
},
],
docs: {
description: {
story: `
### Case à cocher en lecture seule
Cette case à cocher est en lecture seule et ne peut pas être modifiée par l'utilisateur, mais elle n'est pas visuellement désactivée comme la version disabled.
`,
},
},
},
}
export const DifferentDensities: Story = {
parameters: {
sourceCode: [
{
name: 'Template',
code: `
`,
},
],
docs: {
description: {
story: `
### Différentes densités
Le composant SyCheckbox prend en charge différentes densités pour s'adapter à différents contextes d'interface utilisateur.
`,
},
},
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked1 = ref(false)
const checked2 = ref(false)
const checked3 = ref(false)
return { args, checked1, checked2, checked3 }
},
template: `
`,
}),
}
export const CustomColors: Story = {
parameters: {
sourceCode: [
{
name: 'Template',
code: `
`,
},
],
docs: {
description: {
story: `
### Couleurs personnalisées
Le composant SyCheckbox peut être personnalisé avec différentes couleurs pour s'adapter à votre thème.
`,
},
},
},
render: args => ({
components: { SyCheckbox },
setup() {
const checked1 = ref(true)
const checked2 = ref(true)
const checked3 = ref(true)
const checked4 = ref(true)
const checked5 = ref(true)
return { args, checked1, checked2, checked3, checked4, checked5 }
},
template: `
`,
}),
}