From e3a703f0018339798b47e85de200613c573fbc48 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Thu, 14 Mar 2024 12:11:19 +0800 Subject: [PATCH 01/10] feat: support string cell editing --- .../src/lib/cell/CellEditors/string-editor.ts | 27 +++++++++--- apps/frontend/src/lib/table/TableView.svelte | 44 +++++++++++++++++-- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts index a54e08cdd..02a2f8f23 100644 --- a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts @@ -1,6 +1,7 @@ import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' import delay from 'delay' +import htm from 'htm' export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void @@ -13,9 +14,21 @@ export class StringEditor implements Edition.EditorBase { private saveCallback: SaveCallback, ) {} + private initElement() { + const element = this.element + if (!element) return + + element.focus() + + const editCell = this.editCell + if (!editCell) return + + element.value = editCell.model[editCell.prop] as string + } + async componentDidRender() { await delay(0) - this.element?.focus() + this.initElement() } private onChange(e: Event) { @@ -24,10 +37,12 @@ export class StringEditor implements Edition.EditorBase { } render(createComponent: RevoGrid.HyperFunc) { - return createComponent('input', { - onchange: (e: Event) => this.onChange(e), - class: - 'border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5', - }) + const html = htm.bind(createComponent) + return html` + this.onChange(e)} + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> + ` } } diff --git a/apps/frontend/src/lib/table/TableView.svelte b/apps/frontend/src/lib/table/TableView.svelte index da3589d36..8e2e806d7 100644 --- a/apps/frontend/src/lib/table/TableView.svelte +++ b/apps/frontend/src/lib/table/TableView.svelte @@ -3,7 +3,7 @@ import { clickOutside, cn } from '$lib/utils' import { RevoGrid } from '@revolist/svelte-datagrid' import * as DropdownMenu from '$lib/components/ui/dropdown-menu' - import type { RevoGrid as RevoGridType } from '@revolist/revogrid/dist/types/interfaces' + import type { Edition, RevoGrid as RevoGridType } from '@revolist/revogrid/dist/types/interfaces' import type { Components, RevoGridCustomEvent } from '@revolist/revogrid' import { defineCustomElements } from '@revolist/revogrid/loader' import { cellTemplateMap } from '$lib/cell/CellComponents/cell-template' @@ -35,7 +35,8 @@ import * as AlertDialog from '$lib/components/ui/alert-dialog' import ConfirmBulkDeleteRecord from '$lib/record/ConfirmBulkDeleteRecord.svelte' import ConfirmBulkDuplicateRecord from '$lib/record/ConfirmBulkDuplicateRecord.svelte' - import htm from 'htm' + import { toast } from 'svelte-sonner' + import { has } from 'lodash-es' const pinnedPositionMap: Record = { left: 'colPinStart', @@ -193,6 +194,7 @@ size: $view.getFieldWidth(field.id.value), pin: position ? pinnedPositionMap[position] : undefined, autoSize: true, + readonly: $readonly, cellTemplate: cellTemplateMap[field.type], columnTemplate: (h, c) => getColumnTemplate(h, c, $readonly), columnProperties: (column: RevoGridType.ColumnRegular) => { @@ -306,6 +308,41 @@ } } + const updateRecord = trpc().record.update.mutation({ + async onSuccess() { + toast.success($t('RECORD.UPDATED', { ns: 'success' })) + currentRecordId.set(undefined) + }, + onError(error, variables, context) { + toast.error(error.message) + }, + }) + const onAfterEdit = async ( + event: RevoGridCustomEvent, + ) => { + if ($readonly) return + const detail = event.detail + const isSingleEdit = (data: any): data is Edition.BeforeSaveDataDetails => has(data, 'model') + + if (isSingleEdit(detail)) { + $updateRecord.mutate({ + tableId: $table.id.value, + id: detail.model.id, + values: { + [detail.prop]: detail.val, + }, + }) + } else { + // $updateRecord.mutate({ + // tableId: $table.id.value, + // id: detail.mode + // values: { + // [detail.prop]: detail.val, + // }, + // }) + } + } + $: hasRecord = !!$records.length const deleteField = trpc().table.field.delete.mutation({ @@ -337,10 +374,11 @@ theme="compact" range rowClass="id" - readonly + readonly={$readonly} {rowDefinitions} {editors} on:aftercolumnresize={onAfterColumnResize} + on:afteredit={onAfterEdit} /> {#if isLoading}
From 71eabb0e8b8ff4862f68c7e692d1b9f5b7e25701 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Thu, 14 Mar 2024 12:27:10 +0800 Subject: [PATCH 02/10] feat: bulk update --- .../sqlite/record-sqlite.repository.ts | 5 +++ apps/frontend/src/lib/table/TableView.svelte | 32 +++++++++++++++---- packages/trpc/src/router/record.router.ts | 9 ++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts b/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts index cd6eec5e5..1c59c4920 100644 --- a/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts +++ b/apps/backend/src/core/table/adapters/sqlite/record-sqlite.repository.ts @@ -71,4 +71,9 @@ export class NestRecordSqliteRepository extends RecordSqliteRepository { restoreOneById(table: Table, id: string): Promise { return super.restoreOneById(table, id) } + + @UseRequestContext() + updateManyByIds(table: Table, updates: { id: string; spec: IRecordSpec }[]): Promise { + return super.updateManyByIds(table, updates) + } } diff --git a/apps/frontend/src/lib/table/TableView.svelte b/apps/frontend/src/lib/table/TableView.svelte index 8e2e806d7..43454dd4c 100644 --- a/apps/frontend/src/lib/table/TableView.svelte +++ b/apps/frontend/src/lib/table/TableView.svelte @@ -317,6 +317,17 @@ toast.error(error.message) }, }) + + const updateRecords = trpc().record.bulkUpdate.mutation({ + async onSuccess() { + toast.success($t('RECORD.UPDATED', { ns: 'success' })) + currentRecordId.set(undefined) + }, + onError(error, variables, context) { + toast.error(error.message) + }, + }) + const onAfterEdit = async ( event: RevoGridCustomEvent, ) => { @@ -333,13 +344,20 @@ }, }) } else { - // $updateRecord.mutate({ - // tableId: $table.id.value, - // id: detail.mode - // values: { - // [detail.prop]: detail.val, - // }, - // }) + console.log({ detail }) + $updateRecords.mutate({ + tableId: $table.id.value, + records: Object.entries(detail.data).flatMap(([index, d]) => { + return Object.entries(d).map(([fieldId, value]) => { + return { + id: detail.models[Number(index)].id, + values: { + [fieldId]: value, + }, + } + }) + }), + }) } } diff --git a/packages/trpc/src/router/record.router.ts b/packages/trpc/src/router/record.router.ts index 02b2579a3..ef4785c0e 100644 --- a/packages/trpc/src/router/record.router.ts +++ b/packages/trpc/src/router/record.router.ts @@ -12,6 +12,7 @@ import { GetRecordsQuery, RestoreRecordCommand, UpdateRecordCommand, + UpdateRecordsCommand, bulkDeleteRecordsCommandInput, bulkDuplicateRecordsCommandInput, createRecordCommandOutput, @@ -75,6 +76,14 @@ export const createRecordRouter = const cmd = new UpdateRecordCommand(input) return commandBus.execute(cmd) }), + bulkUpdate: procedure + .use(authz('record:update')) + .input(z.any()) + .output(z.void()) + .mutation(({ input }) => { + const cmd = new UpdateRecordsCommand(input) + return commandBus.execute(cmd) + }), delete: procedure .use(authz('record:delete')) .input(deleteRecordCommandInput) From 862e72069ca300da7d2dc9a0248eabff55f8e07d Mon Sep 17 00:00:00 2001 From: nichenqin Date: Thu, 14 Mar 2024 12:41:49 +0800 Subject: [PATCH 03/10] feat: edit number cell --- .../src/lib/cell/CellEditors/editors.ts | 2 + .../src/lib/cell/CellEditors/number-editor.ts | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 apps/frontend/src/lib/cell/CellEditors/number-editor.ts diff --git a/apps/frontend/src/lib/cell/CellEditors/editors.ts b/apps/frontend/src/lib/cell/CellEditors/editors.ts index bdaed4673..66aec7f40 100644 --- a/apps/frontend/src/lib/cell/CellEditors/editors.ts +++ b/apps/frontend/src/lib/cell/CellEditors/editors.ts @@ -1,8 +1,10 @@ import type { Components } from '@revolist/revogrid' import { DateEditor } from './date-editor' +import { NumberEditor } from './number-editor' import { StringEditor } from './string-editor' export const editors: Components.RevoGrid['editors'] = { string: StringEditor, date: DateEditor, + number: NumberEditor, } diff --git a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts new file mode 100644 index 000000000..6ad198ab5 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts @@ -0,0 +1,48 @@ +import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import delay from 'delay' +import htm from 'htm' + +export type SaveCallback = (value: number, preventFocus: boolean) => void + +export class NumberEditor implements Edition.EditorBase { + public element: HTMLInputElement | null = null + public editCell: Edition.EditCell | undefined = undefined + + constructor( + public column: RevoGrid.ColumnRegular, + private saveCallback: SaveCallback, + ) {} + + private initElement() { + const element = this.element + if (!element) return + + element.focus() + + const editCell = this.editCell + if (!editCell) return + + element.value = editCell.model[editCell.prop] as string + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + private onChange(e: Event) { + this.saveCallback(Number((e.target as HTMLInputElement).value), false) + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + return html` + this.onChange(e)} + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> + ` + } +} From 87bd52c847f2bc21195307877ee61fba6ab5887e Mon Sep 17 00:00:00 2001 From: nichenqin Date: Thu, 14 Mar 2024 13:17:38 +0800 Subject: [PATCH 04/10] feat: date number cell --- .../src/lib/cell/CellEditors/date-editor.ts | 30 ++++++++++++++----- .../src/lib/cell/CellEditors/editors.ts | 3 ++ apps/frontend/src/lib/table/TableView.svelte | 3 +- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts index abbda4268..5844f5bea 100644 --- a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts @@ -1,6 +1,7 @@ import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' -import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import { type VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' import delay from 'delay' +import htm from 'htm' export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void @@ -13,9 +14,20 @@ export class DateEditor implements Edition.EditorBase { private saveCallback: SaveCallback, ) {} + private initElement() { + const element = this.element + if (!element) return + + element.focus() + + const editCell = this.editCell + if (!editCell) return + + element.value = editCell.model[editCell.prop] as string + } async componentDidRender() { await delay(0) - this.element?.focus() + this.initElement() } private onChange(e: Event) { @@ -24,11 +36,13 @@ export class DateEditor implements Edition.EditorBase { } render(createComponent: RevoGrid.HyperFunc) { - return createComponent('input', { - type: 'date', - onchange: (e: Event) => this.onChange(e), - class: - 'border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5', - }) + const html = htm.bind(createComponent) + return html` + this.onChange(e)} + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> + ` } } diff --git a/apps/frontend/src/lib/cell/CellEditors/editors.ts b/apps/frontend/src/lib/cell/CellEditors/editors.ts index 66aec7f40..7896f8a1c 100644 --- a/apps/frontend/src/lib/cell/CellEditors/editors.ts +++ b/apps/frontend/src/lib/cell/CellEditors/editors.ts @@ -6,5 +6,8 @@ import { StringEditor } from './string-editor' export const editors: Components.RevoGrid['editors'] = { string: StringEditor, date: DateEditor, + // @ts-expect-error expect number save callback value as number number: NumberEditor, + // @ts-expect-error expect number save callback value as number + currency: NumberEditor, } diff --git a/apps/frontend/src/lib/table/TableView.svelte b/apps/frontend/src/lib/table/TableView.svelte index 43454dd4c..aeeaf2772 100644 --- a/apps/frontend/src/lib/table/TableView.svelte +++ b/apps/frontend/src/lib/table/TableView.svelte @@ -29,7 +29,7 @@ import { confirmDeleteField, createFieldModal } from '$lib/store/modal' import LoadingTable from './LoadingTable.svelte' import TableViewToast from './TableViewToast.svelte' - import { recordSelection, selectedCount, selectedRecords } from '$lib/store/record' + import { recordSelection, selectedCount } from '$lib/store/record' import { getColumnTemplate } from '$lib/field/field-template' import { hasPermission } from '$lib/store/authz' import * as AlertDialog from '$lib/components/ui/alert-dialog' @@ -344,7 +344,6 @@ }, }) } else { - console.log({ detail }) $updateRecords.mutate({ tableId: $table.id.value, records: Object.entries(detail.data).flatMap(([index, d]) => { From e147b1372a6c184dc7b82ce28b35bc208fffcc6a Mon Sep 17 00:00:00 2001 From: nichenqin Date: Thu, 14 Mar 2024 15:42:05 +0800 Subject: [PATCH 05/10] feat: email field --- .../src/lib/cell/CellEditors/base-editor.ts | 33 +++++++++++++++ .../src/lib/cell/CellEditors/date-editor.ts | 2 +- .../src/lib/cell/CellEditors/editors.ts | 2 + .../src/lib/cell/CellEditors/email-editor.ts | 41 +++++++++++++++++++ .../table/field/fields/email/email-field.ts | 4 +- 5 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 apps/frontend/src/lib/cell/CellEditors/base-editor.ts create mode 100644 apps/frontend/src/lib/cell/CellEditors/email-editor.ts diff --git a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts new file mode 100644 index 000000000..b3e475ade --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts @@ -0,0 +1,33 @@ +import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { BaseField } from '@undb/core' +import { toast } from 'svelte-sonner' + +export type SaveCallback = (value: any, preventFocus: boolean) => void + +export abstract class BaseEditor implements Edition.EditorBase { + element?: HTMLInputElement | null | undefined + editCell?: Edition.EditCell | undefined + + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) {} + + protected get field(): T { + return this.column.field as T + } + + onChange(value: V) { + const result = this.field.valueSchema.safeParse(value) + if (result.success) { + this.element?.blur() + this.saveCallback(result.data, false) + } else { + toast.warning(result.error.flatten((i) => i.message).formErrors.join('\n')) + } + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + render(createElement?: RevoGrid.HyperFunc | undefined): string | void | VNode | VNode[] {} +} diff --git a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts index 5844f5bea..9e523a976 100644 --- a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts @@ -1,5 +1,5 @@ import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' -import { type VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' import delay from 'delay' import htm from 'htm' diff --git a/apps/frontend/src/lib/cell/CellEditors/editors.ts b/apps/frontend/src/lib/cell/CellEditors/editors.ts index 7896f8a1c..7a117627e 100644 --- a/apps/frontend/src/lib/cell/CellEditors/editors.ts +++ b/apps/frontend/src/lib/cell/CellEditors/editors.ts @@ -1,11 +1,13 @@ import type { Components } from '@revolist/revogrid' import { DateEditor } from './date-editor' +import { EmailEditor } from './email-editor' import { NumberEditor } from './number-editor' import { StringEditor } from './string-editor' export const editors: Components.RevoGrid['editors'] = { string: StringEditor, date: DateEditor, + email: EmailEditor, // @ts-expect-error expect number save callback value as number number: NumberEditor, // @ts-expect-error expect number save callback value as number diff --git a/apps/frontend/src/lib/cell/CellEditors/email-editor.ts b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts new file mode 100644 index 000000000..eddcf1ae0 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts @@ -0,0 +1,41 @@ +import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { EmailField } from '@undb/core' +import delay from 'delay' +import htm from 'htm' +import { BaseEditor } from './base-editor' + +export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void + +export class EmailEditor extends BaseEditor { + public element: HTMLInputElement | null = null + public editCell: Edition.EditCell | undefined = undefined + + private initElement() { + const element = this.element + if (!element) return + + element.focus() + + const editCell = this.editCell + if (!editCell) return + + element.value = editCell.model[editCell.prop] as string + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + return html` + this.onChange((e.target as HTMLInputElement).value)} + placeholder="example@email.com" + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> + ` + } +} diff --git a/packages/core/src/table/field/fields/email/email-field.ts b/packages/core/src/table/field/fields/email/email-field.ts index 8891b3dbc..e7caab56f 100644 --- a/packages/core/src/table/field/fields/email/email-field.ts +++ b/packages/core/src/table/field/fields/email/email-field.ts @@ -48,7 +48,7 @@ export class EmailField extends BaseField { } get valueSchema() { - const email = z.string() - return this.required ? email.email() : email.nullable() + const email = z.string().email() + return this.required ? email : email.nullable() } } From bd1548418f3998de4f570b2dffcb826b73d00e29 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Thu, 14 Mar 2024 15:51:06 +0800 Subject: [PATCH 06/10] feat: base field editor --- .../src/lib/cell/CellEditors/base-editor.ts | 6 +++++ .../src/lib/cell/CellEditors/date-editor.ts | 19 ++++----------- .../src/lib/cell/CellEditors/editors.ts | 2 -- .../src/lib/cell/CellEditors/email-editor.ts | 2 -- .../src/lib/cell/CellEditors/number-editor.ts | 17 ++++---------- .../src/lib/cell/CellEditors/string-editor.ts | 23 ++++--------------- 6 files changed, 19 insertions(+), 50 deletions(-) diff --git a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts index b3e475ade..2b11c3051 100644 --- a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts @@ -1,6 +1,7 @@ import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' import type { BaseField } from '@undb/core' +import { isEmpty } from 'lodash-es' import { toast } from 'svelte-sonner' export type SaveCallback = (value: any, preventFocus: boolean) => void @@ -19,6 +20,11 @@ export abstract class BaseEditor implements Edition.EditorB } onChange(value: V) { + if (this.field.required && isEmpty(value)) { + this.element?.blur() + return + } + const result = this.field.valueSchema.safeParse(value) if (result.success) { this.element?.blur() diff --git a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts index 9e523a976..4674e1cb0 100644 --- a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts @@ -1,19 +1,13 @@ import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { DateField } from '@undb/core' import delay from 'delay' import htm from 'htm' +import { BaseEditor } from './base-editor' export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void -export class DateEditor implements Edition.EditorBase { - public element: HTMLInputElement | null = null - public editCell: Edition.EditCell | undefined = undefined - - constructor( - public column: RevoGrid.ColumnRegular, - private saveCallback: SaveCallback, - ) {} - +export class DateEditor extends BaseEditor { private initElement() { const element = this.element if (!element) return @@ -30,17 +24,12 @@ export class DateEditor implements Edition.EditorBase { this.initElement() } - private onChange(e: Event) { - this.element?.blur() - this.saveCallback((e.target as HTMLInputElement).valueAsDate?.toISOString() ?? '', false) - } - render(createComponent: RevoGrid.HyperFunc) { const html = htm.bind(createComponent) return html` this.onChange(e)} + onchange=${(e: Event) => this.onChange((e.target as HTMLInputElement).valueAsDate?.toISOString() ?? '')} class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" /> ` diff --git a/apps/frontend/src/lib/cell/CellEditors/editors.ts b/apps/frontend/src/lib/cell/CellEditors/editors.ts index 7a117627e..e1b6cf245 100644 --- a/apps/frontend/src/lib/cell/CellEditors/editors.ts +++ b/apps/frontend/src/lib/cell/CellEditors/editors.ts @@ -8,8 +8,6 @@ export const editors: Components.RevoGrid['editors'] = { string: StringEditor, date: DateEditor, email: EmailEditor, - // @ts-expect-error expect number save callback value as number number: NumberEditor, - // @ts-expect-error expect number save callback value as number currency: NumberEditor, } diff --git a/apps/frontend/src/lib/cell/CellEditors/email-editor.ts b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts index eddcf1ae0..f5b6718e2 100644 --- a/apps/frontend/src/lib/cell/CellEditors/email-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts @@ -5,8 +5,6 @@ import delay from 'delay' import htm from 'htm' import { BaseEditor } from './base-editor' -export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void - export class EmailEditor extends BaseEditor { public element: HTMLInputElement | null = null public editCell: Edition.EditCell | undefined = undefined diff --git a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts index 6ad198ab5..a541db04f 100644 --- a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts @@ -1,19 +1,14 @@ import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { CurrencyField, NumberField } from '@undb/core' import delay from 'delay' import htm from 'htm' +import { BaseEditor } from './base-editor' -export type SaveCallback = (value: number, preventFocus: boolean) => void - -export class NumberEditor implements Edition.EditorBase { +export class NumberEditor extends BaseEditor { public element: HTMLInputElement | null = null public editCell: Edition.EditCell | undefined = undefined - constructor( - public column: RevoGrid.ColumnRegular, - private saveCallback: SaveCallback, - ) {} - private initElement() { const element = this.element if (!element) return @@ -31,16 +26,12 @@ export class NumberEditor implements Edition.EditorBase { this.initElement() } - private onChange(e: Event) { - this.saveCallback(Number((e.target as HTMLInputElement).value), false) - } - render(createComponent: RevoGrid.HyperFunc) { const html = htm.bind(createComponent) return html` this.onChange(e)} + onblur=${(e: Event) => this.onChange(Number((e.target as HTMLInputElement).value))} class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" /> ` diff --git a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts index 02a2f8f23..cc621cb6a 100644 --- a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts @@ -1,19 +1,11 @@ -import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { StringField } from '@undb/core' import delay from 'delay' import htm from 'htm' +import { BaseEditor } from './base-editor' -export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void - -export class StringEditor implements Edition.EditorBase { - public element: HTMLInputElement | null = null - public editCell: Edition.EditCell | undefined = undefined - - constructor( - public column: RevoGrid.ColumnRegular, - private saveCallback: SaveCallback, - ) {} - +export class StringEditor extends BaseEditor { private initElement() { const element = this.element if (!element) return @@ -31,16 +23,11 @@ export class StringEditor implements Edition.EditorBase { this.initElement() } - private onChange(e: Event) { - this.element?.blur() - this.saveCallback((e.target as HTMLInputElement).value, false) - } - render(createComponent: RevoGrid.HyperFunc) { const html = htm.bind(createComponent) return html` this.onChange(e)} + onchange=${(e: Event) => this.onChange((e.target as HTMLInputElement).value)} class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" /> ` From bcf56e33ba1db7178dd2088a981bfb226ab72f51 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Thu, 14 Mar 2024 18:07:14 +0800 Subject: [PATCH 07/10] feat: number input use zag --- apps/frontend/package.json | 6 +- .../src/lib/cell/CellEditors/base-editor.ts | 12 +- .../src/lib/cell/CellEditors/date-editor.ts | 6 +- .../src/lib/cell/CellEditors/email-editor.ts | 2 +- .../src/lib/cell/CellEditors/normalizer.ts | 3 + .../src/lib/cell/CellEditors/number-editor.ts | 48 +++-- .../src/lib/cell/CellEditors/string-editor.ts | 2 +- pnpm-lock.yaml | 180 +++++++++++------- 8 files changed, 167 insertions(+), 92 deletions(-) create mode 100644 apps/frontend/src/lib/cell/CellEditors/normalizer.ts diff --git a/apps/frontend/package.json b/apps/frontend/package.json index cef280669..896956dc2 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -98,5 +98,9 @@ "xlsx": "^0.18.5", "zod": "^3.22.4" }, - "type": "module" + "type": "module", + "dependencies": { + "@zag-js/number-input": "^0.38.1", + "@zag-js/types": "^0.38.1" + } } diff --git a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts index 2b11c3051..db76e227b 100644 --- a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts @@ -6,8 +6,8 @@ import { toast } from 'svelte-sonner' export type SaveCallback = (value: any, preventFocus: boolean) => void -export abstract class BaseEditor implements Edition.EditorBase { - element?: HTMLInputElement | null | undefined +export abstract class BaseEditor implements Edition.EditorBase { + element?: E | null | undefined editCell?: Edition.EditCell | undefined constructor( @@ -19,15 +19,19 @@ export abstract class BaseEditor implements Edition.EditorB return this.column.field as T } + // TODO: describe type onChange(value: V) { + // TODO: better check updates + if (value === this.editCell?.model[this.editCell.prop]) { + return + } + if (this.field.required && isEmpty(value)) { - this.element?.blur() return } const result = this.field.valueSchema.safeParse(value) if (result.success) { - this.element?.blur() this.saveCallback(result.data, false) } else { toast.warning(result.error.flatten((i) => i.message).formErrors.join('\n')) diff --git a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts index 4674e1cb0..1aa90aedf 100644 --- a/apps/frontend/src/lib/cell/CellEditors/date-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/date-editor.ts @@ -1,13 +1,11 @@ -import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' import type { DateField } from '@undb/core' import delay from 'delay' import htm from 'htm' import { BaseEditor } from './base-editor' -export type SaveCallback = (value: Edition.SaveData, preventFocus: boolean) => void - -export class DateEditor extends BaseEditor { +export class DateEditor extends BaseEditor { private initElement() { const element = this.element if (!element) return diff --git a/apps/frontend/src/lib/cell/CellEditors/email-editor.ts b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts index f5b6718e2..bcb5ec379 100644 --- a/apps/frontend/src/lib/cell/CellEditors/email-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/email-editor.ts @@ -5,7 +5,7 @@ import delay from 'delay' import htm from 'htm' import { BaseEditor } from './base-editor' -export class EmailEditor extends BaseEditor { +export class EmailEditor extends BaseEditor { public element: HTMLInputElement | null = null public editCell: Edition.EditCell | undefined = undefined diff --git a/apps/frontend/src/lib/cell/CellEditors/normalizer.ts b/apps/frontend/src/lib/cell/CellEditors/normalizer.ts new file mode 100644 index 000000000..ef3071df4 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/normalizer.ts @@ -0,0 +1,3 @@ +import { createNormalizer } from '@zag-js/types' + +export const normalizer = createNormalizer((v) => v) diff --git a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts index a541db04f..4431b8c27 100644 --- a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts @@ -1,24 +1,40 @@ import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' import type { CurrencyField, NumberField } from '@undb/core' +import * as numberInput from '@zag-js/number-input' import delay from 'delay' import htm from 'htm' -import { BaseEditor } from './base-editor' +import { BaseEditor, type SaveCallback } from './base-editor' +import { normalizer } from './normalizer' -export class NumberEditor extends BaseEditor { +export class NumberEditor extends BaseEditor { public element: HTMLInputElement | null = null public editCell: Edition.EditCell | undefined = undefined + private api: numberInput.Api | null = null - private initElement() { - const element = this.element - if (!element) return + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) { + super(column, saveCallback) + + const service = numberInput.machine({ + id: this.column.prop as string, + }) + const machine = service.start() + + const api = numberInput.connect(machine.state, machine.send, normalizer) - element.focus() + this.api = api + } + private initElement() { const editCell = this.editCell if (!editCell) return - element.value = editCell.model[editCell.prop] as string + const value = editCell.model[editCell.prop] as string + this.api?.setValue(Number(value)) + this.api?.focus() } async componentDidRender() { @@ -28,12 +44,20 @@ export class NumberEditor extends BaseEditor { render(createComponent: RevoGrid.HyperFunc) { const html = htm.bind(createComponent) + const api = this.api + return html` - this.onChange(Number((e.target as HTMLInputElement).value))} - class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" - /> +
+ { + const value = (e.target as HTMLInputElement).value + return this.onChange(parseInt(value.replace(/,/g, ''), 10)) + }} + class="border-2 border-primary-300 rounded-none text-gray-900 text-sm focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" + /> +
` } } diff --git a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts index cc621cb6a..07b3dcedb 100644 --- a/apps/frontend/src/lib/cell/CellEditors/string-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/string-editor.ts @@ -5,7 +5,7 @@ import delay from 'delay' import htm from 'htm' import { BaseEditor } from './base-editor' -export class StringEditor extends BaseEditor { +export class StringEditor extends BaseEditor { private initElement() { const element = this.element if (!element) return diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22abed73a..ec3bf6e41 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -465,6 +465,13 @@ importers: version: 1.1.0 apps/frontend: + dependencies: + '@zag-js/number-input': + specifier: ^0.38.1 + version: 0.38.1 + '@zag-js/types': + specifier: ^0.38.1 + version: 0.38.1 devDependencies: '@playwright/test': specifier: ^1.40.1 @@ -757,7 +764,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -824,7 +831,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) type-fest: specifier: ^4.8.3 version: 4.8.3 @@ -891,7 +898,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -925,7 +932,7 @@ importers: version: link:../../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1068,7 +1075,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) type-fest: specifier: ^4.8.3 version: 4.8.3 @@ -1127,7 +1134,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1179,7 +1186,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1204,7 +1211,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1271,7 +1278,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1314,7 +1321,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1357,7 +1364,7 @@ importers: version: link:../tsconfig tsup: specifier: ^8.0.1 - version: 8.0.1(typescript@5.3.3) + version: 8.0.1(@swc/core@1.4.2)(ts-node@10.9.2)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -2940,6 +2947,12 @@ packages: '@swc/helpers': 0.5.6 dev: true + /@internationalized/number@3.5.1: + resolution: {integrity: sha512-N0fPU/nz15SwR9IbfJ5xaS9Ss/O5h1sVXMZf43vc9mxEG48ovglvvzBjF53aHlq20uoR6c+88CrIXipU/LSzwg==} + dependencies: + '@swc/helpers': 0.5.6 + dev: false + /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} @@ -6136,7 +6149,6 @@ packages: resolution: {integrity: sha512-aYX01Ke9hunpoCexYAgQucEpARGQ5w/cqHFrIR+e9gdKb1QWTsVJuTJ2ozQzIAxLyRQe/m+2RqzkyOOGiMKRQA==} dependencies: tslib: 2.6.2 - dev: true /@swc/types@0.1.5: resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==} @@ -6547,7 +6559,7 @@ packages: /@types/ioredis@4.28.10: resolution: {integrity: sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==} dependencies: - '@types/node': 20.10.5 + '@types/node': 20.11.20 dev: false /@types/istanbul-lib-coverage@2.0.4: @@ -6706,7 +6718,6 @@ packages: resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} dependencies: undici-types: 5.26.5 - dev: true /@types/nodemailer@6.4.14: resolution: {integrity: sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==} @@ -7305,6 +7316,79 @@ packages: /@xtuc/long@4.2.2: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + /@zag-js/anatomy@0.38.1: + resolution: {integrity: sha512-y6foq9vX+EfjfCwi9DMt5gI9eU7kshFjioidACI+u8TjBG2Z3nOjvEq+3Ct+dy5v/aRwsvSquaXpB555e0OLNQ==} + dev: false + + /@zag-js/core@0.38.1: + resolution: {integrity: sha512-v1WKbIzOWN2yN450zxVA1QCnI8np1vvcpPwsor9ZLM8OnION6yeiKCyjI7DqmLebCMhN9wnjExkjcb8ZAmNDuA==} + dependencies: + '@zag-js/store': 0.38.1 + klona: 2.0.6 + dev: false + + /@zag-js/dom-event@0.38.1: + resolution: {integrity: sha512-+EkCNsS9oE8ZtgUU7G9EVXrZKcCaIJlSEVCliFjYUpDgo3Jxl1sOwbSIqaIi/yKIuJSl/lswz3jCxue0BW2bWw==} + dependencies: + '@zag-js/text-selection': 0.38.1 + '@zag-js/types': 0.38.1 + dev: false + + /@zag-js/dom-query@0.38.1: + resolution: {integrity: sha512-bGtc3hfBY4ngxHNTohT2XAwHpKkbPMeUF5JggSETMMtfv9e+FLy4F79j7OWjJjvQZKKcVesrw/1s0TlhkvZioA==} + dev: false + + /@zag-js/form-utils@0.38.1: + resolution: {integrity: sha512-o4G80b/XHhGUy4pJnTdJW9TwfOREXhiafSv6YQ5Zpk0EPi5lk1IroYL6ZJT6/vuvirc+HVzE+znvlYOfDl5PVQ==} + dependencies: + '@zag-js/mutation-observer': 0.38.1 + dev: false + + /@zag-js/mutation-observer@0.38.1: + resolution: {integrity: sha512-y3JdkLTxE+5J1BWIkVwyc+IDCSUW2DgHxR9UHUUW/uRPe3SG5/MDQGupdVy/dUH4WTi/bcFwXkpfBxBP1+idFw==} + dev: false + + /@zag-js/number-input@0.38.1: + resolution: {integrity: sha512-zjnAvF9IYHeg7aOcDbmXAKLOEykaHhBmkCzggAITHtL6JrZRCp6UftI8OpwltETsHpSMi+ANwj4oLdS0PWEhkg==} + dependencies: + '@internationalized/number': 3.5.1 + '@zag-js/anatomy': 0.38.1 + '@zag-js/core': 0.38.1 + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/form-utils': 0.38.1 + '@zag-js/mutation-observer': 0.38.1 + '@zag-js/number-utils': 0.38.1 + '@zag-js/types': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + + /@zag-js/number-utils@0.38.1: + resolution: {integrity: sha512-4DHzyxSxlRFhKoY7hUz3s2rRcjZhiqSBLQ8CE/QRQyQoHww/QaCFqZT6NT0d1ZOU0IRPvUszVr/2I8PbIr9LSA==} + dev: false + + /@zag-js/store@0.38.1: + resolution: {integrity: sha512-gaOsP8jjqZnivZSmzj3xHtpd8Vm9KMo3ESp41iinyry5suSgEn7BV12dTGG90+DBAfuCggqYv/dLjQCxbqQeMA==} + dependencies: + proxy-compare: 2.6.0 + dev: false + + /@zag-js/text-selection@0.38.1: + resolution: {integrity: sha512-FNcYOIlH21rBdiZCaFsaCRDtbmr5WBNEXiqfS8dFWx/x1MxNZ9iyDnBLRGy7OQnTGsyLdpCdHTtGjX65EkKGAw==} + dependencies: + '@zag-js/dom-query': 0.38.1 + dev: false + + /@zag-js/types@0.38.1: + resolution: {integrity: sha512-kSpjSE+d+5bucALf5DYaHloekk5V0OjlyOowqEEUEjCipGpPLWPxRXSKjiSxQIFftZij07sLxjn609b8PTKrEw==} + dependencies: + csstype: 3.1.3 + dev: false + + /@zag-js/utils@0.38.1: + resolution: {integrity: sha512-kJ15yxO5tWCxZSMVIBSYPE8nfHA9zqtaOlZ8IiFDPPPi137SJDjKz/VIXlSUyCd/af7kQTCnxqVyNFLiyxGaRw==} + dev: false + /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -9190,6 +9274,10 @@ packages: cssom: 0.3.8 dev: true + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + dev: false + /cz-conventional-changelog@3.3.0(@types/node@20.10.5)(typescript@5.3.3): resolution: {integrity: sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==} engines: {node: '>= 10'} @@ -12669,6 +12757,11 @@ packages: engines: {node: '>=6'} dev: true + /klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + dev: false + /knex@2.5.1(better-sqlite3@8.7.0): resolution: {integrity: sha512-z78DgGKUr4SE/6cm7ku+jHvFT0X97aERh/f0MUKAKgFnwCYBEW4TFBqtHWFYiJFid7fMrtpZ/gxJthvz5mEByA==} engines: {node: '>=12'} @@ -15392,22 +15485,6 @@ packages: yaml: 1.10.2 dev: true - /postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - dependencies: - lilconfig: 3.0.0 - yaml: 2.3.4 - dev: true - /postcss-load-config@4.0.2(postcss@8.4.32): resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} engines: {node: '>= 14'} @@ -15751,6 +15828,10 @@ packages: - supports-color dev: false + /proxy-compare@2.6.0: + resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==} + dev: false + /proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: false @@ -18294,45 +18375,6 @@ packages: - ts-node dev: true - /tsup@8.0.1(typescript@5.3.3): - resolution: {integrity: sha512-hvW7gUSG96j53ZTSlT4j/KL0q1Q2l6TqGBFc6/mu/L46IoNWqLLUzLRLP1R8Q7xrJTmkDxxDoojV5uCVs1sVOg==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - dependencies: - bundle-require: 4.0.1(esbuild@0.19.7) - cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@5.5.0) - esbuild: 0.19.7 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - postcss-load-config: 4.0.2 - resolve-from: 5.0.0 - rollup: 4.5.1 - source-map: 0.8.0-beta.0 - sucrase: 3.32.0 - tree-kill: 1.2.2 - typescript: 5.3.3 - transitivePeerDependencies: - - supports-color - - ts-node - dev: true - /tuf-js@2.1.0: resolution: {integrity: sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==} engines: {node: ^16.14.0 || >=18.0.0} From d41b236e0a39d85b1994807a5241be417dd2fa3e Mon Sep 17 00:00:00 2001 From: nichenqin Date: Fri, 15 Mar 2024 10:23:30 +0800 Subject: [PATCH 08/10] feat(wip): color picker --- apps/frontend/package.json | 1 + .../src/lib/cell/CellEditors/base-editor.ts | 7 +- .../src/lib/cell/CellEditors/color-editor.ts | 82 +++++++++++++++++++ .../src/lib/cell/CellEditors/editors.ts | 2 + .../src/lib/cell/CellEditors/number-editor.ts | 20 +++-- pnpm-lock.yaml | 70 +++++++++++++++- 6 files changed, 168 insertions(+), 14 deletions(-) create mode 100644 apps/frontend/src/lib/cell/CellEditors/color-editor.ts diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 896956dc2..6097864d6 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -100,6 +100,7 @@ }, "type": "module", "dependencies": { + "@zag-js/color-picker": "^0.38.1", "@zag-js/number-input": "^0.38.1", "@zag-js/types": "^0.38.1" } diff --git a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts index db76e227b..2a082a963 100644 --- a/apps/frontend/src/lib/cell/CellEditors/base-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/base-editor.ts @@ -10,6 +10,10 @@ export abstract class BaseEditor impleme element?: E | null | undefined editCell?: Edition.EditCell | undefined + componentDidRender(): void {} + disconnectedCallback(): void {} + abstract render(createElement?: RevoGrid.HyperFunc | undefined): string | void | VNode | VNode[] + constructor( public column: RevoGrid.ColumnRegular, protected saveCallback: SaveCallback, @@ -37,7 +41,4 @@ export abstract class BaseEditor impleme toast.warning(result.error.flatten((i) => i.message).formErrors.join('\n')) } } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - render(createElement?: RevoGrid.HyperFunc | undefined): string | void | VNode | VNode[] {} } diff --git a/apps/frontend/src/lib/cell/CellEditors/color-editor.ts b/apps/frontend/src/lib/cell/CellEditors/color-editor.ts new file mode 100644 index 000000000..81f229641 --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/color-editor.ts @@ -0,0 +1,82 @@ +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { ColorField } from '@undb/core' +import * as colorPicker from '@zag-js/color-picker' +import delay from 'delay' +import htm from 'htm' +import { BaseEditor, type SaveCallback } from './base-editor' +import { normalizer } from './normalizer' + +export class ColorEditor extends BaseEditor { + private api: colorPicker.Api + private service: ReturnType + + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) { + super(column, saveCallback) + + const service = colorPicker.machine({ + id: this.column.prop as string, + open: true, + positioning: { + strategy: 'fixed', + placement: 'bottom-start', + }, + }) + this.service = service + const machine = service.start() + + const api = colorPicker.connect(machine.state, machine.send, normalizer) + this.api = api + } + + private initElement() { + const editCell = this.editCell + if (!editCell) return + + const value = editCell.model[editCell.prop] as string + if (value) { + const parsed = colorPicker.parse(value) + this.api.setValue(parsed) + } + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + disconnectedCallback(): void { + this.service.stop() + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + const api = this.api + + return html` +
+ + +
+ + +
+ +
+
+
+
+
+
+
+
+
+ ` + } +} diff --git a/apps/frontend/src/lib/cell/CellEditors/editors.ts b/apps/frontend/src/lib/cell/CellEditors/editors.ts index e1b6cf245..1216b7fa5 100644 --- a/apps/frontend/src/lib/cell/CellEditors/editors.ts +++ b/apps/frontend/src/lib/cell/CellEditors/editors.ts @@ -1,4 +1,5 @@ import type { Components } from '@revolist/revogrid' +import { ColorEditor } from './color-editor' import { DateEditor } from './date-editor' import { EmailEditor } from './email-editor' import { NumberEditor } from './number-editor' @@ -10,4 +11,5 @@ export const editors: Components.RevoGrid['editors'] = { email: EmailEditor, number: NumberEditor, currency: NumberEditor, + color: ColorEditor, } diff --git a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts index 4431b8c27..10112b936 100644 --- a/apps/frontend/src/lib/cell/CellEditors/number-editor.ts +++ b/apps/frontend/src/lib/cell/CellEditors/number-editor.ts @@ -1,4 +1,4 @@ -import type { Edition, RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' import type { CurrencyField, NumberField } from '@undb/core' import * as numberInput from '@zag-js/number-input' @@ -8,9 +8,8 @@ import { BaseEditor, type SaveCallback } from './base-editor' import { normalizer } from './normalizer' export class NumberEditor extends BaseEditor { - public element: HTMLInputElement | null = null - public editCell: Edition.EditCell | undefined = undefined - private api: numberInput.Api | null = null + private api: numberInput.Api + private service: ReturnType constructor( public column: RevoGrid.ColumnRegular, @@ -21,6 +20,7 @@ export class NumberEditor extends BaseEditor) { const html = htm.bind(createComponent) const api = this.api return html` -
+
{ const value = (e.target as HTMLInputElement).value return this.onChange(parseInt(value.replace(/,/g, ''), 10)) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec3bf6e41..b5b1b1281 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -466,6 +466,9 @@ importers: apps/frontend: dependencies: + '@zag-js/color-picker': + specifier: ^0.38.1 + version: 0.38.1 '@zag-js/number-input': specifier: ^0.38.1 version: 0.38.1 @@ -2802,18 +2805,15 @@ packages: resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} dependencies: '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/dom@1.6.3: resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} dependencies: '@floating-ui/core': 1.6.0 '@floating-ui/utils': 0.2.1 - dev: true /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - dev: true /@fortawesome/fontawesome-common-types@6.5.1: resolution: {integrity: sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==} @@ -7320,6 +7320,30 @@ packages: resolution: {integrity: sha512-y6foq9vX+EfjfCwi9DMt5gI9eU7kshFjioidACI+u8TjBG2Z3nOjvEq+3Ct+dy5v/aRwsvSquaXpB555e0OLNQ==} dev: false + /@zag-js/color-picker@0.38.1: + resolution: {integrity: sha512-Ae0ivxHAqX9+gJWRnci8iPYR/HQvyTQOxc1kCwSY077XiW0BqlQACf0DYVBOw/dXQSoBRsgHzyOJ71M1e1PFoA==} + dependencies: + '@zag-js/anatomy': 0.38.1 + '@zag-js/color-utils': 0.38.1 + '@zag-js/core': 0.38.1 + '@zag-js/dismissable': 0.38.1 + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/form-utils': 0.38.1 + '@zag-js/popper': 0.38.1 + '@zag-js/tabbable': 0.38.1 + '@zag-js/text-selection': 0.38.1 + '@zag-js/types': 0.38.1 + '@zag-js/utils': 0.38.1 + '@zag-js/visually-hidden': 0.38.1 + dev: false + + /@zag-js/color-utils@0.38.1: + resolution: {integrity: sha512-y/8mKFlPqiNNSPdb22qEUYDqeYm/S/j8IvdkHUg2zdyCIeShUd2D5y7u1oSQUQphskzmIoGp8y7HrQ0xVKY93g==} + dependencies: + '@zag-js/numeric-range': 0.38.1 + dev: false + /@zag-js/core@0.38.1: resolution: {integrity: sha512-v1WKbIzOWN2yN450zxVA1QCnI8np1vvcpPwsor9ZLM8OnION6yeiKCyjI7DqmLebCMhN9wnjExkjcb8ZAmNDuA==} dependencies: @@ -7327,6 +7351,15 @@ packages: klona: 2.0.6 dev: false + /@zag-js/dismissable@0.38.1: + resolution: {integrity: sha512-a7PxUb3+gS27RKRAKJv8voj5BZ4mHpZeMJqECjpYTTlsDjmzHnW4rLCB1m/uq/odiVAaLqJs55jZyskezdOoyg==} + dependencies: + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/interact-outside': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + /@zag-js/dom-event@0.38.1: resolution: {integrity: sha512-+EkCNsS9oE8ZtgUU7G9EVXrZKcCaIJlSEVCliFjYUpDgo3Jxl1sOwbSIqaIi/yKIuJSl/lswz3jCxue0BW2bWw==} dependencies: @@ -7344,6 +7377,15 @@ packages: '@zag-js/mutation-observer': 0.38.1 dev: false + /@zag-js/interact-outside@0.38.1: + resolution: {integrity: sha512-VAsYIFVZk6ceTBAGBsFEo1Rqt9IMGzFYRn8NnBeGgbAOamDyJMCfU80QfBOma5xqcTtcBajsT6svIupKxTem9w==} + dependencies: + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/tabbable': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + /@zag-js/mutation-observer@0.38.1: resolution: {integrity: sha512-y3JdkLTxE+5J1BWIkVwyc+IDCSUW2DgHxR9UHUUW/uRPe3SG5/MDQGupdVy/dUH4WTi/bcFwXkpfBxBP1+idFw==} dev: false @@ -7367,12 +7409,30 @@ packages: resolution: {integrity: sha512-4DHzyxSxlRFhKoY7hUz3s2rRcjZhiqSBLQ8CE/QRQyQoHww/QaCFqZT6NT0d1ZOU0IRPvUszVr/2I8PbIr9LSA==} dev: false + /@zag-js/numeric-range@0.38.1: + resolution: {integrity: sha512-X3sn4pz3iHed/LGg7foXsSIpDD7P9OmMF/NsfCQMP7/BpexlX6gNNcTmayWxzW+dut4YNyeKg8oivlk5maUI8Q==} + dev: false + + /@zag-js/popper@0.38.1: + resolution: {integrity: sha512-S/yqW2IpdM3VybGmiD+dOg8YEPIsSI9qKbnL1Mw1ntTEsp2NLOUDuShDbFvU/khTCax9ehGQiqB7g8+pXiClMw==} + dependencies: + '@floating-ui/dom': 1.6.3 + '@zag-js/dom-query': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + /@zag-js/store@0.38.1: resolution: {integrity: sha512-gaOsP8jjqZnivZSmzj3xHtpd8Vm9KMo3ESp41iinyry5suSgEn7BV12dTGG90+DBAfuCggqYv/dLjQCxbqQeMA==} dependencies: proxy-compare: 2.6.0 dev: false + /@zag-js/tabbable@0.38.1: + resolution: {integrity: sha512-xPrC4FmRlrupYf+KQ3+yN3bXaJa2TxUQAY/IWubYm7lRJnEsxhELV7IpbxUHsTRFrLvwTjs61y8TFtnY6CfWIQ==} + dependencies: + '@zag-js/dom-query': 0.38.1 + dev: false + /@zag-js/text-selection@0.38.1: resolution: {integrity: sha512-FNcYOIlH21rBdiZCaFsaCRDtbmr5WBNEXiqfS8dFWx/x1MxNZ9iyDnBLRGy7OQnTGsyLdpCdHTtGjX65EkKGAw==} dependencies: @@ -7389,6 +7449,10 @@ packages: resolution: {integrity: sha512-kJ15yxO5tWCxZSMVIBSYPE8nfHA9zqtaOlZ8IiFDPPPi137SJDjKz/VIXlSUyCd/af7kQTCnxqVyNFLiyxGaRw==} dev: false + /@zag-js/visually-hidden@0.38.1: + resolution: {integrity: sha512-8l1lYn9ilq8EAP2wZOHnlTqK3MJvIfrzMvxXQd5UMbTiQEDzjEwFFqROedjVvDhAZJ/riCGmlvFy4P0a6J2adA==} + dev: false + /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true From 8ee3ccb96f83cff620e20253979de919cf492677 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Fri, 15 Mar 2024 11:09:18 +0800 Subject: [PATCH 09/10] chore: trpc logger link --- apps/frontend/src/lib/record/CreateRecord.svelte | 15 ++++++++++----- apps/frontend/src/lib/trpc/client.ts | 7 ++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/frontend/src/lib/record/CreateRecord.svelte b/apps/frontend/src/lib/record/CreateRecord.svelte index 6e0188a77..0a1d43dad 100644 --- a/apps/frontend/src/lib/record/CreateRecord.svelte +++ b/apps/frontend/src/lib/record/CreateRecord.svelte @@ -10,7 +10,7 @@ import * as Dialog from '$lib/components/ui/dialog' import { Button } from '$lib/components/ui/button' import { createRecordForm } from '$lib/store/table' - import { RecordFactory, type Field, WithRecordId, RecordId } from '@undb/core' + import { RecordFactory, type Field, WithRecordId, RecordId, Record } from '@undb/core' import Badge from '$components/ui/badge/badge.svelte' import CreateRecordItem from './CreateRecordItem.svelte' import { me } from '$lib/store/me' @@ -69,7 +69,10 @@ $: values = pick($form, keys($tainted)) const id = RecordId.create() - $: tempRecord = RecordFactory.temp($table, values, $me.userId, new WithRecordId(id)) + let tempRecord: Record | undefined + $: if ($me) { + tempRecord = RecordFactory.temp($table, values, $me.userId, new WithRecordId(id)) + } @@ -92,9 +95,11 @@
- {#each fields as field (field.id.value)} - - {/each} + {#if tempRecord} + {#each fields as field (field.id.value)} + + {/each} + {/if}
diff --git a/apps/frontend/src/lib/trpc/client.ts b/apps/frontend/src/lib/trpc/client.ts index 6fca3a4a6..e9413f087 100644 --- a/apps/frontend/src/lib/trpc/client.ts +++ b/apps/frontend/src/lib/trpc/client.ts @@ -1,9 +1,14 @@ import type { AppRouter } from '@undb/trpc' -import { createTRPCSvelte, httpBatchLink } from 'trpc-svelte-query' +import { createTRPCSvelte, httpBatchLink, loggerLink } from 'trpc-svelte-query' export const trpc = () => createTRPCSvelte({ links: [ + loggerLink({ + enabled: (opts) => + (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') || + (opts.direction === 'down' && opts.result instanceof Error), + }), httpBatchLink({ url: '/api/trpc', }), From 236a32d1d0bc18225e79aef2eee6e9680e4aed81 Mon Sep 17 00:00:00 2001 From: nichenqin Date: Fri, 15 Mar 2024 12:44:22 +0800 Subject: [PATCH 10/10] feat(wip): select picker --- apps/frontend/package.json | 1 + .../src/lib/cell/CellEditors/editors.ts | 2 + .../src/lib/cell/CellEditors/select-editor.ts | 82 +++++++++++++++++++ pnpm-lock.yaml | 29 +++++++ 4 files changed, 114 insertions(+) create mode 100644 apps/frontend/src/lib/cell/CellEditors/select-editor.ts diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 6097864d6..d8ec5a76f 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -101,6 +101,7 @@ "type": "module", "dependencies": { "@zag-js/color-picker": "^0.38.1", + "@zag-js/combobox": "^0.38.1", "@zag-js/number-input": "^0.38.1", "@zag-js/types": "^0.38.1" } diff --git a/apps/frontend/src/lib/cell/CellEditors/editors.ts b/apps/frontend/src/lib/cell/CellEditors/editors.ts index 1216b7fa5..9251279e1 100644 --- a/apps/frontend/src/lib/cell/CellEditors/editors.ts +++ b/apps/frontend/src/lib/cell/CellEditors/editors.ts @@ -3,6 +3,7 @@ import { ColorEditor } from './color-editor' import { DateEditor } from './date-editor' import { EmailEditor } from './email-editor' import { NumberEditor } from './number-editor' +import { SelectEditor } from './select-editor' import { StringEditor } from './string-editor' export const editors: Components.RevoGrid['editors'] = { @@ -12,4 +13,5 @@ export const editors: Components.RevoGrid['editors'] = { number: NumberEditor, currency: NumberEditor, color: ColorEditor, + select: SelectEditor, } diff --git a/apps/frontend/src/lib/cell/CellEditors/select-editor.ts b/apps/frontend/src/lib/cell/CellEditors/select-editor.ts new file mode 100644 index 000000000..b06d0897a --- /dev/null +++ b/apps/frontend/src/lib/cell/CellEditors/select-editor.ts @@ -0,0 +1,82 @@ +import type { RevoGrid } from '@revolist/revogrid/dist/types/interfaces' +import type { VNode } from '@revolist/revogrid/dist/types/stencil-public-runtime' +import type { SelectField } from '@undb/core' +import * as combobox from '@zag-js/combobox' +import delay from 'delay' +import htm from 'htm' +import { BaseEditor, type SaveCallback } from './base-editor' +import { normalizer } from './normalizer' + +export class SelectEditor extends BaseEditor { + private api: combobox.Api + private service: ReturnType + + private get options() { + return this.field.options.options.map((o) => o.toJSON()) + } + constructor( + public column: RevoGrid.ColumnRegular, + protected saveCallback: SaveCallback, + ) { + super(column, saveCallback) + + const collection = combobox.collection({ + items: this.options, + itemToValue: (o) => o.key, + itemToString: (o) => o.name, + }) + const service = combobox.machine({ + id: this.column.prop as string, + collection, + }) + + this.service = service + const machine = service.start() + + const api = combobox.connect(machine.state, machine.send, normalizer) + this.api = api + } + + private initElement() { + const editCell = this.editCell + if (!editCell) return + + const value = editCell.model[editCell.prop] as string | null + if (value) { + this.api.setValue([value]) + } + } + + disconnectedCallback(): void { + this.service.stop() + } + + async componentDidRender() { + await delay(0) + this.initElement() + } + + render(createComponent: RevoGrid.HyperFunc) { + const html = htm.bind(createComponent) + const { api, options } = this + return html` +
+
+ +
+ + +
+
+
    + ${options.map((item) => { + return html`
  • ${item.name}
  • ` + })} +
+ } +
+
+
+ ` + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5b1b1281..a7899e1a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -469,6 +469,9 @@ importers: '@zag-js/color-picker': specifier: ^0.38.1 version: 0.38.1 + '@zag-js/combobox': + specifier: ^0.38.1 + version: 0.38.1 '@zag-js/number-input': specifier: ^0.38.1 version: 0.38.1 @@ -7320,6 +7323,16 @@ packages: resolution: {integrity: sha512-y6foq9vX+EfjfCwi9DMt5gI9eU7kshFjioidACI+u8TjBG2Z3nOjvEq+3Ct+dy5v/aRwsvSquaXpB555e0OLNQ==} dev: false + /@zag-js/aria-hidden@0.38.1: + resolution: {integrity: sha512-n0qP/w8tXxvpZp0F2U+I4WYDW24/yqp49eP6kSo+Av9M4E9F8/o17yGxu30/dli3/KthsCjkde+0cfZqHs/Duw==} + dependencies: + '@zag-js/dom-query': 0.38.1 + dev: false + + /@zag-js/collection@0.38.1: + resolution: {integrity: sha512-Z+73tmgLS/KgKVJiTQQX9ujTo2MaYhx5G9yMvZ15G3zLZx8DoFGcKmFl3RvuDgmnTGjcLpV+Tn76O5mZKpHOkA==} + dev: false + /@zag-js/color-picker@0.38.1: resolution: {integrity: sha512-Ae0ivxHAqX9+gJWRnci8iPYR/HQvyTQOxc1kCwSY077XiW0BqlQACf0DYVBOw/dXQSoBRsgHzyOJ71M1e1PFoA==} dependencies: @@ -7344,6 +7357,22 @@ packages: '@zag-js/numeric-range': 0.38.1 dev: false + /@zag-js/combobox@0.38.1: + resolution: {integrity: sha512-S01hBrYcUPRrmzT0GDYMrRIxggUXBL9Fn5FlBvNVBqVHHJUyTVBSMB8Va7omKRK/Y2gspEhrodggxSzwwOZvEg==} + dependencies: + '@zag-js/anatomy': 0.38.1 + '@zag-js/aria-hidden': 0.38.1 + '@zag-js/collection': 0.38.1 + '@zag-js/core': 0.38.1 + '@zag-js/dismissable': 0.38.1 + '@zag-js/dom-event': 0.38.1 + '@zag-js/dom-query': 0.38.1 + '@zag-js/mutation-observer': 0.38.1 + '@zag-js/popper': 0.38.1 + '@zag-js/types': 0.38.1 + '@zag-js/utils': 0.38.1 + dev: false + /@zag-js/core@0.38.1: resolution: {integrity: sha512-v1WKbIzOWN2yN450zxVA1QCnI8np1vvcpPwsor9ZLM8OnION6yeiKCyjI7DqmLebCMhN9wnjExkjcb8ZAmNDuA==} dependencies: