From e2b85be69843ee456808d4a2ef849d4c0d94dd6a Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Tue, 14 Nov 2023 09:51:01 +0100 Subject: [PATCH 01/15] fix: #241 - add min-content for alert container --- packages/theme/src/alert.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/theme/src/alert.scss b/packages/theme/src/alert.scss index 76c11090..dbed9c54 100644 --- a/packages/theme/src/alert.scss +++ b/packages/theme/src/alert.scss @@ -1,7 +1,7 @@ @use './common/typography.scss'; .puik-alert { - @apply relative flex flex-row p-4 border text-primary-800 items-start; + @apply relative min-w-fit flex flex-row items-start p-4 border text-primary-800; &--success { @apply bg-green-50 border border-green; .puik-alert__icon { @@ -30,7 +30,7 @@ @apply border-0; } &__container { - @apply flex flex-col md:flex-row w-full; + @apply flex flex-col md:flex-row md:items-start w-full; } &__content { @apply flex flex-row flex-grow; @@ -46,7 +46,7 @@ @extend .puik-body-default; } &__button { - @apply text-sm px-4 py-3 mt-2 ml-9 md:m-0; + @apply text-sm px-4 py-3 mt-2 ml-9 md:m-0 h-auto; } &__icon { @apply mt-0.5 flex-shrink-0; From e1e18de3a0d60864a20bc99adc061f6be9c1b14a Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Tue, 14 Nov 2023 16:46:15 +0100 Subject: [PATCH 02/15] fix: #241 - min height for button component --- packages/tailwind-preset/theme.js | 5 +++++ packages/theme/src/alert.scss | 2 +- packages/theme/src/button.scss | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/tailwind-preset/theme.js b/packages/tailwind-preset/theme.js index 0d0b162a..bd71ccb2 100644 --- a/packages/tailwind-preset/theme.js +++ b/packages/tailwind-preset/theme.js @@ -93,6 +93,11 @@ module.exports = { screens: { xs: '320px', }, + minHeight: { + sm: '1.75rem', + md: '2.25rem', + lg: '3rem', + }, opacity: { overlay: '0.8', }, diff --git a/packages/theme/src/alert.scss b/packages/theme/src/alert.scss index dbed9c54..2d865d51 100644 --- a/packages/theme/src/alert.scss +++ b/packages/theme/src/alert.scss @@ -46,7 +46,7 @@ @extend .puik-body-default; } &__button { - @apply text-sm px-4 py-3 mt-2 ml-9 md:m-0 h-auto; + @apply mt-2 ml-9 md:m-0; } &__icon { @apply mt-0.5 flex-shrink-0; diff --git a/packages/theme/src/button.scss b/packages/theme/src/button.scss index f9922b2d..7adf1acd 100644 --- a/packages/theme/src/button.scss +++ b/packages/theme/src/button.scss @@ -6,16 +6,16 @@ &--sm { @extend .puik-text-button-small; - @apply py-1 px-2 h-7; + @apply py-1 px-2 min-h-sm; } &--md { - @apply h-9; + @apply min-h-md; } &--lg { @extend .puik-text-button-large; - @apply py-3.5 px-4 gap-3 h-12; + @apply py-3.5 px-4 gap-3 min-h-lg; } &--fluid { From 0cfc5becf64c9f7dce3ea7ac02d6f6838c84de13 Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Fri, 17 Nov 2023 22:57:33 +0100 Subject: [PATCH 03/15] feat: [table] - sticky columns (wip) --- packages/components/table/src/table.ts | 15 +++++++++ packages/components/table/src/table.vue | 31 ++++++++++++++++--- .../components/table/stories/table.stories.ts | 24 ++++++++++++++ packages/theme/src/table.scss | 21 +++++++++++++ 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/packages/components/table/src/table.ts b/packages/components/table/src/table.ts index 61cce8f3..68a463a5 100644 --- a/packages/components/table/src/table.ts +++ b/packages/components/table/src/table.ts @@ -35,6 +35,21 @@ export const tableProps = buildProps({ required: false, default: false, }, + stickyFirstCol: { + type: Boolean, + required: false, + default: false, + }, + stickyLastCol: { + type: Boolean, + required: false, + default: false, + }, + stickyHeader: { + type: Boolean, + required: false, + default: false, + }, } as const) export type TableProps = ExtractPropTypes diff --git a/packages/components/table/src/table.vue b/packages/components/table/src/table.vue index 7e7af7cf..bf864648 100644 --- a/packages/components/table/src/table.vue +++ b/packages/components/table/src/table.vue @@ -5,7 +5,10 @@ @@ -49,7 +52,10 @@ > {{ item[header.value] }} @@ -93,6 +102,20 @@ const emit = defineEmits<{ const { t } = useLocale() const checked = ref(props.selection) +const isSticky = ( + index: number, + selectable: boolean = props.selectable +): boolean => { + if (selectable) { + return props.stickyLastCol && index === props.headers.length - 1 + } else { + return ( + (props.stickyFirstCol && index === 0) || + (props.stickyLastCol && index === props.headers.length - 1) + ) + } +} + const selectAll = computed(() => { if (indeterminate.value) return false return checked.value.length === props.items.length diff --git a/packages/components/table/stories/table.stories.ts b/packages/components/table/stories/table.stories.ts index 3be1d3f0..b51c445d 100644 --- a/packages/components/table/stories/table.stories.ts +++ b/packages/components/table/stories/table.stories.ts @@ -88,6 +88,30 @@ export default { }, }, }, + stickyFirstCol: { + control: 'boolean', + description: 'Makes the first column sticky', + table: { + type: { summary: 'boolean' }, + defaultValue: { summary: 'false' }, + }, + }, + stickyLastCol: { + control: 'boolean', + description: 'Makes the last column sticky', + table: { + type: { summary: 'boolean' }, + defaultValue: { summary: 'false' }, + }, + }, + stickyHeader: { + control: 'boolean', + description: 'Makes the header sticky', + table: { + type: { summary: 'boolean' }, + defaultValue: { summary: 'false' }, + }, + }, '`header-${header.value}`': { control: 'none', description: 'Slot to replace header', diff --git a/packages/theme/src/table.scss b/packages/theme/src/table.scss index 43aa1888..d9833f3e 100644 --- a/packages/theme/src/table.scss +++ b/packages/theme/src/table.scss @@ -72,4 +72,25 @@ } } } + .puik-table__head__row__item--sticky, + .puik-table__body__row__item--sticky { + @apply sticky bg-white; + &::before { + @apply content-[''] block absolute top-0 bottom-0 w-1.5 bg-white; + } + } + tr .puik-table__head__row__item--sticky:first-child, + tr .puik-table__body__row__item--sticky:first-child { + @apply -left-px; + &::before { + @apply right-0 shadow-[4px_0_7px_-1px_rgba(29,29,27,0.1)]; + } + } + tr .puik-table__head__row__item--sticky:last-child, + tr .puik-table__body__row__item--sticky:last-child { + @apply -right-px; + &::before { + @apply left-0 shadow-[-4px_0_7px_-1px_rgba(29,29,27,0.1)]; + } + } } From 8da09e6de0e4345c085f5a6de45b1576d3b16ef2 Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Mon, 20 Nov 2023 10:23:46 +0100 Subject: [PATCH 04/15] feat: [table] sticky col - add style on hover --- packages/theme/src/table.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/theme/src/table.scss b/packages/theme/src/table.scss index d9833f3e..79743790 100644 --- a/packages/theme/src/table.scss +++ b/packages/theme/src/table.scss @@ -61,7 +61,10 @@ > tr { @apply border-t-[1px]; &:hover { - @apply bg-primary-200; + td, + td::before { + @apply bg-primary-200; + } } &__item, > td { @@ -72,6 +75,7 @@ } } } + .puik-table__head__row__item--sticky, .puik-table__body__row__item--sticky { @apply sticky bg-white; From 52403d6fcf0edc243282f6e3911b6144f419300b Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Mon, 20 Nov 2023 14:42:08 +0100 Subject: [PATCH 05/15] test: [table] - test sticky behavior --- packages/components/table/test/table.spec.ts | 74 +++++++++++++++++--- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/packages/components/table/test/table.spec.ts b/packages/components/table/test/table.spec.ts index c2b41532..bb22d4b4 100644 --- a/packages/components/table/test/table.spec.ts +++ b/packages/components/table/test/table.spec.ts @@ -10,8 +10,8 @@ const defaultItems = Array(5) .fill(null) .map(() => { return { - firstname: faker.name.firstName(), - lastname: faker.name.lastName(), + firstname: faker.person.firstName(), + lastname: faker.person.lastName(), } }) @@ -23,20 +23,40 @@ describe('Table tests', () => { const getTable = () => wrapper.find('.puik-table') const getHeaders = () => wrapper.findAll(`.${headerColClass}`) const getRows = () => wrapper.findAll('.puik-table__body__row') - const getCols = (rowIndex) => getRows()[rowIndex].findAll(`.${colClass}`) - const getRowCheckbox = (rowIndex) => + const getCols = (rowIndex: number): HTMLElement => + getRows()[rowIndex].findAll(`.${colClass}`) + const getAllItemsOfCol = (colIndex: number) => { + const allItems: Array = [] + getRows().map((row, rowIndex) => { + const Item: HTMLElement = getCols(rowIndex)[colIndex] + allItems.push(Item) + }) + return allItems + } + const getRowCheckbox = (rowIndex: number) => getRows()[rowIndex].find(`.${colClass}--selection__checkbox`) const getAllRowCheckbox = () => wrapper.findAll(`.${colClass}--selection__checkbox`) const getHeaderCheckbox = () => wrapper.find(`.${headerColClass}--selection__checkbox`) - const isCheckboxChecked = (checkbox) => - checkbox.find('.puik-checkbox__input:checked').exists() - const isCheckboxInderminate = (checkbox) => - checkbox.find('.puik-checkbox__input:indeterminate').exists() + const isCheckboxChecked = (checkbox: { + find: (arg0: string) => { + (): any + new (): any + exists: { (): any; new (): any } + } + }) => checkbox.find('.puik-checkbox__input:checked').exists() + const isCheckboxInderminate = (checkbox: { + find: (arg0: string) => { + (): any + new (): any + exists: { (): any; new (): any } + } + }) => checkbox.find('.puik-checkbox__input:indeterminate').exists() - const getCheckboxLabel = (checkbox) => checkbox.find('.puik-checkbox__label') + const getCheckboxLabel = (checkbox: { find: (arg0: string) => any }) => + checkbox.find('.puik-checkbox__label') const factory = ( propsData: Record = {}, @@ -83,7 +103,8 @@ describe('Table tests', () => { expect(displayedItems[1].text()).toBe(defaultItems[0].lastname) }) it('should display item using slot', () => { - const getIinitials = (item) => item.firstname[0] + item.lastname[0] + const getIinitials = (item: { firstname: any; lastname: any }) => + item.firstname[0] + item.lastname[0] const headers: PuikTableHeader[] = [{ value: 'initials' }] factory( { headers }, @@ -248,4 +269,37 @@ describe('Table tests', () => { const table = getTable() expect(table.classes()).toContain('puik-table--full-width') }) + + it('should have selectable column sticky', () => { + const headers: PuikTableHeader[] = [ + { value: 'firstname' }, + { value: 'lastname' }, + ] + factory({ headers, selectable: true, stickyFirstCol: true }) + const header = getHeaders()[0] + const allFirstItems = getAllItemsOfCol(0) + expect(header.classes()).toContain('puik-table__head__row__item--selection') + expect(header.classes()).toContain('puik-table__head__row__item--sticky') + allFirstItems.map((firstItemRow) => { + expect(firstItemRow.classes()).toContain( + 'puik-table__body__row__item--sticky' + ) + }) + }) + + it('should have last column sticky', () => { + const headers: PuikTableHeader[] = [ + { value: 'firstname' }, + { value: 'lastname' }, + ] + factory({ headers, stickyLastCol: true }) + const header = getHeaders()[1] + const allLastItems = getAllItemsOfCol(1) + expect(header.classes()).toContain('puik-table__head__row__item--sticky') + allLastItems.map((lastItemRow) => { + expect(lastItemRow.classes()).toContain( + 'puik-table__body__row__item--sticky' + ) + }) + }) }) From 5bcc50f5e38a6d2f954d5afd1b8b7a9b18f019dc Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Mon, 20 Nov 2023 15:10:19 +0100 Subject: [PATCH 06/15] docs: [table] update storybook (sticky cols) --- packages/components/table/src/table.ts | 5 - .../components/table/stories/table.stories.ts | 154 +++++++++++++++++- 2 files changed, 146 insertions(+), 13 deletions(-) diff --git a/packages/components/table/src/table.ts b/packages/components/table/src/table.ts index 68a463a5..80c93839 100644 --- a/packages/components/table/src/table.ts +++ b/packages/components/table/src/table.ts @@ -45,11 +45,6 @@ export const tableProps = buildProps({ required: false, default: false, }, - stickyHeader: { - type: Boolean, - required: false, - default: false, - }, } as const) export type TableProps = ExtractPropTypes diff --git a/packages/components/table/stories/table.stories.ts b/packages/components/table/stories/table.stories.ts index b51c445d..3a82638c 100644 --- a/packages/components/table/stories/table.stories.ts +++ b/packages/components/table/stories/table.stories.ts @@ -104,14 +104,6 @@ export default { defaultValue: { summary: 'false' }, }, }, - stickyHeader: { - control: 'boolean', - description: 'Makes the header sticky', - table: { - type: { summary: 'boolean' }, - defaultValue: { summary: 'false' }, - }, - }, '`header-${header.value}`': { control: 'none', description: 'Slot to replace header', @@ -528,6 +520,7 @@ export const Selectable: StoryObj = { }, }, } + export const FullWidth: StoryObj = { render: Template, args: { @@ -599,6 +592,151 @@ export const FullWidth: StoryObj = { }, } +export const stickyColumns: StoryObj = { + render: Template, + args: { + selectable: true, + stickyFirstCol: true, + stickyLastCol: true, + }, + parameters: { + docs: { + source: { + code: ` + + const headers: PuikTableHeader[] = [ + { + text: 'Nom', + value: 'lastname', + size: 'md', + }, + { + text: 'Prénom', + value: 'firstname', + size: 'md', + }, + { + text: 'Age', + value: 'age', + size: 'sm', + align: 'center', + }, + { + text: 'Email', + value: 'email', + align: 'right', + }, + { + value: 'actions', + size: 'sm', + }, + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
NomPrénomAgeEmail
+
+ + +
+
lastname0firstname040lastname0.firstname0@email.com + +
+
+ + +
+
lastname1firstname140lastname1.firstname1@email.com + +
+
+ + +
+
lastname2firstname240lastname2.firstname2@email.com + +
+ `, + language: 'html', + }, + }, + }, +} + const ColSizesTemplate: StoryFn = (args: Args) => ({ components: { PuikTable, From 56200925192827033e7b86bedbefcf1e533a89fb Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Mon, 20 Nov 2023 15:50:14 +0100 Subject: [PATCH 07/15] fix: #250 [table] sticky cols --- .../components/table/stories/table.stories.ts | 160 +++++++++--------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/packages/components/table/stories/table.stories.ts b/packages/components/table/stories/table.stories.ts index 3a82638c..ff3361f5 100644 --- a/packages/components/table/stories/table.stories.ts +++ b/packages/components/table/stories/table.stories.ts @@ -650,86 +650,86 @@ export const stickyColumns: StoryObj = { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
-
NomPrénomAgeEmail
-
- - -
-
lastname0firstname040lastname0.firstname0@email.com - -
-
- - -
-
lastname1firstname140lastname1.firstname1@email.com - -
-
- - -
-
lastname2firstname240lastname2.firstname2@email.com - -
+ + + +
+ + +
+ + Nom + Prénom + Age + Email + + + + + + +
+ + +
+ + lastname0 + firstname0 + 40 + lastname0.firstname0@email.com + + + + + + +
+ + +
+ + lastname1 + firstname1 + 40 + lastname1.firstname1@email.com + + + + + + +
+ + +
+ + lastname2 + firstname2 + 40 + lastname2.firstname2@email.com + + + + + + `, language: 'html', }, From 0affd2c9166aad9b3c937a3e9fb02477e6a6c7ee Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Mon, 20 Nov 2023 18:32:58 +0100 Subject: [PATCH 08/15] feat: [table] expanded cell (wip) --- packages/components/table/src/table.vue | 85 +++++++++++++++---------- packages/theme/src/table.scss | 4 +- 2 files changed, 54 insertions(+), 35 deletions(-) diff --git a/packages/components/table/src/table.vue b/packages/components/table/src/table.vue index bf864648..b1cdd1de 100644 --- a/packages/components/table/src/table.vue +++ b/packages/components/table/src/table.vue @@ -45,40 +45,51 @@ - - - + + - {{ getSelectLabel(rowIndex) }} - - - - - {{ item[header.value] }} - - - + + {{ getSelectLabel(rowIndex) }} + + + + + + {{ item[header.value] }} + + + + + + + {{ item }} + + + + @@ -101,6 +112,7 @@ const emit = defineEmits<{ }>() const { t } = useLocale() const checked = ref(props.selection) +const expandedCell = ref(null) const isSticky = ( index: number, @@ -116,6 +128,13 @@ const isSticky = ( } } +// const expandCell = (rowIndex: number, cellIndex: number) => { +// expandedCell.value = { +// content: rows.value[rowIndex][cellIndex], +// rowIndex, +// } +// } + const selectAll = computed(() => { if (indeterminate.value) return false return checked.value.length === props.items.length diff --git a/packages/theme/src/table.scss b/packages/theme/src/table.scss index 79743790..39fe27b0 100644 --- a/packages/theme/src/table.scss +++ b/packages/theme/src/table.scss @@ -61,8 +61,8 @@ > tr { @apply border-t-[1px]; &:hover { - td, - td::before { + .puik-table__body__row__item, + .puik-table__body__row__item::before { @apply bg-primary-200; } } From 8e063b368c59c4a85e7bf281bb4cee3208f3fb3b Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Tue, 21 Nov 2023 18:10:35 +0100 Subject: [PATCH 09/15] feat: [table] expandable rows (wip) --- packages/components/table/src/table.ts | 5 ++ packages/components/table/src/table.vue | 81 +++++++++++++------ .../components/table/stories/table.stories.ts | 8 ++ packages/theme/src/table.scss | 18 ++++- 4 files changed, 86 insertions(+), 26 deletions(-) diff --git a/packages/components/table/src/table.ts b/packages/components/table/src/table.ts index 80c93839..12274792 100644 --- a/packages/components/table/src/table.ts +++ b/packages/components/table/src/table.ts @@ -20,6 +20,11 @@ export const tableProps = buildProps({ required: false, default: () => [], }, + expandable: { + type: Boolean, + required: false, + default: false, + }, selectable: { type: Boolean, required: false, diff --git a/packages/components/table/src/table.vue b/packages/components/table/src/table.vue index b1cdd1de..cef9b884 100644 --- a/packages/components/table/src/table.vue +++ b/packages/components/table/src/table.vue @@ -4,13 +4,16 @@ + - - {{ getSelectLabel(rowIndex) }} - +
+ + {{ getSelectLabel(rowIndex) }} + + +
- - - + + + {{ item }} - - - + + + @@ -99,6 +122,7 @@ import { computed, ref, watch } from 'vue' import { useLocale } from '@puik/hooks' import PuikCheckbox from '../../checkbox/src/checkbox.vue' +import PuikIcon from '../../icon/src/icon.vue' import { tableProps } from './table' defineOptions({ name: 'PuikTable', @@ -112,13 +136,14 @@ const emit = defineEmits<{ }>() const { t } = useLocale() const checked = ref(props.selection) -const expandedCell = ref(null) +const expandedRows = ref([]) const isSticky = ( index: number, - selectable: boolean = props.selectable + selectable: boolean = props.selectable, + expandable: boolean = props.expandable ): boolean => { - if (selectable) { + if (selectable || expandable) { return props.stickyLastCol && index === props.headers.length - 1 } else { return ( @@ -128,13 +153,23 @@ const isSticky = ( } } -// const expandCell = (rowIndex: number, cellIndex: number) => { -// expandedCell.value = { -// content: rows.value[rowIndex][cellIndex], -// rowIndex, +// const expandRow = (rowIndex: number) => { +// if (expandedRow.value === rowIndex) { +// return (expandedRow.value = null) +// } else { +// return (expandedRow.value = rowIndex) // } // } +const expandRow = (rowIndex: number) => { + const position = expandedRows.value.indexOf(rowIndex) + if (position !== -1) { + expandedRows.value.splice(position, 1) + } else { + expandedRows.value.push(rowIndex) + } +} + const selectAll = computed(() => { if (indeterminate.value) return false return checked.value.length === props.items.length diff --git a/packages/components/table/stories/table.stories.ts b/packages/components/table/stories/table.stories.ts index ff3361f5..49efb633 100644 --- a/packages/components/table/stories/table.stories.ts +++ b/packages/components/table/stories/table.stories.ts @@ -56,6 +56,14 @@ export default { }, }, }, + expandable: { + control: 'boolean', + description: 'Makes rows expandable', + table: { + type: { summary: 'boolean' }, + defaultValue: { summary: 'false' }, + }, + }, selectable: { control: 'boolean', description: 'Add col with checkbox', diff --git a/packages/theme/src/table.scss b/packages/theme/src/table.scss index 39fe27b0..4735b6b2 100644 --- a/packages/theme/src/table.scss +++ b/packages/theme/src/table.scss @@ -58,7 +58,8 @@ &__body, > tbody { &__row, - > tr { + > .puik-table__head__row, + .puik-table__body__row { @apply border-t-[1px]; &:hover { .puik-table__body__row__item, @@ -66,8 +67,7 @@ @apply bg-primary-200; } } - &__item, - > td { + &__item { @extend .puik-body-default; @apply text-primary-800; @include puik-table-item(); @@ -97,4 +97,16 @@ @apply left-0 shadow-[-4px_0_7px_-1px_rgba(29,29,27,0.1)]; } } + .puik-table__body__row__item--expanded { + @apply p-0; + } + .puik-table__body__row__item__container { + @apply flex items-center space-x-4; + .puik-icon { + @apply select-none cursor-pointer -rotate-0 transform transition-transform duration-150 ease-in-out; + } + .puik-icon__expand { + @apply -rotate-180 transform transition-transform duration-100 ease-in-out; + } + } } From e343f4964f25f4e2e93cbbbf2fb70c1e90d2385a Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Wed, 22 Nov 2023 10:58:31 +0100 Subject: [PATCH 10/15] feat: [table] related #250 - refacto style for sticky cols --- packages/components/table/src/table.vue | 73 ++++++++++++++++--- .../components/table/stories/table.stories.ts | 3 + packages/theme/src/table.scss | 65 ++++++++++++----- 3 files changed, 113 insertions(+), 28 deletions(-) diff --git a/packages/components/table/src/table.vue b/packages/components/table/src/table.vue index cef9b884..a77e42b5 100644 --- a/packages/components/table/src/table.vue +++ b/packages/components/table/src/table.vue @@ -1,5 +1,5 @@