@dxos/react-ui-mosaic 0.9.1-staging.ee54ba693a → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/chunk-Mosaic.mjs +1024 -0
- package/dist/lib/chunk-Mosaic.mjs.map +1 -0
- package/dist/lib/index.mjs +653 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/playwright.mjs +200 -0
- package/dist/lib/playwright.mjs.map +1 -0
- package/dist/lib/testing.mjs +127 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +11 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/components/Board/Board.d.ts +7 -27
- package/dist/types/src/components/Board/Board.d.ts.map +1 -1
- package/dist/types/src/components/Board/Board.stories.d.ts.map +1 -1
- package/dist/types/src/components/Board/BoardColumnContext.d.ts +10 -0
- package/dist/types/src/components/Board/BoardColumnContext.d.ts.map +1 -0
- package/dist/types/src/components/Board/BoardContext.d.ts +26 -0
- package/dist/types/src/components/Board/BoardContext.d.ts.map +1 -0
- package/dist/types/src/components/Board/Column.d.ts +2 -7
- package/dist/types/src/components/Board/Column.d.ts.map +1 -1
- package/dist/types/src/components/Board/index.d.ts +2 -0
- package/dist/types/src/components/Board/index.d.ts.map +1 -1
- package/dist/types/src/components/Focus/Focus.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Container.d.ts +6 -34
- package/dist/types/src/components/Mosaic/Container.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Mosaic.d.ts +10 -15
- package/dist/types/src/components/Mosaic/Mosaic.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/MosaicContainerContext.d.ts +34 -0
- package/dist/types/src/components/Mosaic/MosaicContainerContext.d.ts.map +1 -0
- package/dist/types/src/components/Mosaic/MosaicTileContext.d.ts +31 -0
- package/dist/types/src/components/Mosaic/MosaicTileContext.d.ts.map +1 -0
- package/dist/types/src/components/Mosaic/Placeholder.d.ts +3 -3
- package/dist/types/src/components/Mosaic/Placeholder.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Stack.d.ts +8 -2
- package/dist/types/src/components/Mosaic/Stack.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Stack.stories.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Tile.d.ts +6 -32
- package/dist/types/src/components/Mosaic/Tile.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/VirtualStackPagination.stories.d.ts +13 -0
- package/dist/types/src/components/Mosaic/VirtualStackPagination.stories.d.ts.map +1 -0
- package/dist/types/src/components/Mosaic/index.d.ts +0 -1
- package/dist/types/src/components/Mosaic/index.d.ts.map +1 -1
- package/dist/types/src/components/SearchStack/SearchStack.d.ts +1 -1
- package/dist/types/src/components/SearchStack/SearchStack.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useDefaultColumnEventHandler.d.ts +2 -2
- package/dist/types/src/hooks/useDefaultColumnEventHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useEventHandlerAdapter.d.ts +3 -3
- package/dist/types/src/hooks/useEventHandlerAdapter.d.ts.map +1 -1
- package/dist/types/src/hooks/useVirtualizerPagination.d.ts +60 -0
- package/dist/types/src/hooks/useVirtualizerPagination.d.ts.map +1 -0
- package/dist/types/src/hooks/useVirtualizerPagination.test.d.ts +2 -0
- package/dist/types/src/hooks/useVirtualizerPagination.test.d.ts.map +1 -0
- package/dist/types/src/hooks/useVisibleItems.d.ts +2 -2
- package/dist/types/src/hooks/useVisibleItems.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +35 -37
- package/src/components/Board/Board.stories.tsx +7 -6
- package/src/components/Board/Board.tsx +9 -54
- package/src/components/Board/BoardColumnContext.ts +25 -0
- package/src/components/Board/BoardContext.ts +43 -0
- package/src/components/Board/Column.tsx +13 -27
- package/src/components/Board/Item.tsx +2 -2
- package/src/components/Board/index.ts +3 -0
- package/src/components/Mosaic/Container.tsx +31 -53
- package/src/components/Mosaic/DragHandle.tsx +1 -1
- package/src/components/Mosaic/{Mosaic.tsx → Mosaic.ts} +5 -16
- package/src/components/Mosaic/MosaicContainerContext.ts +44 -0
- package/src/components/Mosaic/MosaicTileContext.ts +34 -0
- package/src/components/Mosaic/Placeholder.tsx +7 -8
- package/src/components/Mosaic/ResizeHandle.stories.tsx +4 -4
- package/src/components/Mosaic/ResizeHandle.tsx +2 -2
- package/src/components/Mosaic/Stack.stories.tsx +49 -13
- package/src/components/Mosaic/Stack.tsx +30 -9
- package/src/components/Mosaic/Tile.tsx +33 -33
- package/src/components/Mosaic/VirtualStackPagination.stories.tsx +423 -0
- package/src/components/Mosaic/index.ts +0 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDefaultColumnEventHandler.ts +2 -2
- package/src/hooks/useEventHandlerAdapter.ts +4 -5
- package/src/hooks/useVirtualizerPagination.test.tsx +105 -0
- package/src/hooks/useVirtualizerPagination.ts +473 -0
- package/src/hooks/useVisibleItems.ts +2 -2
- package/src/playwright/smoke.spec.ts +4 -1
- package/src/testing/DefaultStackTile.tsx +1 -1
- package/src/testing/decorator.tsx +3 -3
- package/dist/lib/browser/chunk-OBVIYZLR.mjs +0 -1119
- package/dist/lib/browser/chunk-OBVIYZLR.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -701
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/playwright/index.mjs +0 -256
- package/dist/lib/browser/playwright/index.mjs.map +0 -7
- package/dist/lib/browser/testing/index.mjs +0 -136
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/browser/translations.mjs +0 -18
- package/dist/lib/browser/translations.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-4IEMCMIV.mjs +0 -1121
- package/dist/lib/node-esm/chunk-4IEMCMIV.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -702
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/playwright/index.mjs +0 -258
- package/dist/lib/node-esm/playwright/index.mjs.map +0 -7
- package/dist/lib/node-esm/testing/index.mjs +0 -137
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/translations.mjs +0 -20
- package/dist/lib/node-esm/translations.mjs.map +0 -7
- package/dist/types/src/components/Mosaic/Root.d.ts +0 -35
- package/dist/types/src/components/Mosaic/Root.d.ts.map +0 -1
- package/dist/types/src/components/Mosaic/types.d.ts +0 -86
- package/dist/types/src/components/Mosaic/types.d.ts.map +0 -1
- package/src/components/Mosaic/Root.tsx +0 -288
- package/src/components/Mosaic/types.ts +0 -94
- /package/src/components/Focus/{Focus.tsx → Focus.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/Board/BoardColumnContext.ts","../../src/components/Board/BoardContext.ts","../../src/hooks/useContainerDebug.tsx","../../src/hooks/useEventHandlerAdapter.ts","../../src/hooks/useDefaultColumnEventHandler.ts","../../src/components/Mosaic/extension.ts","../../src/components/Board/Item.tsx","../../src/components/Board/Column.tsx","../../src/components/Board/Board.tsx","../../src/components/SearchStack/SearchStack.tsx"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { createContext } from '@radix-ui/react-context';\n\n// Kept out of `Column.tsx`: react-refresh only fast-refreshes a module whose exports are all\n// components, so the context and hook exported beside them force a full page reload on every edit.\n\nexport const BOARD_COLUMN_CONTEXT_NAME = 'Board.Column';\n\nexport type BoardColumnContextValue<TColumn = unknown> = {\n column: TColumn;\n};\n\nexport const [BoardColumnProvider, useBoardColumnContext] = createContext<BoardColumnContextValue | null>(\n BOARD_COLUMN_CONTEXT_NAME,\n null,\n);\n\n/** Returns the current column when rendered inside a board column (e.g., in column header or item tile). */\nexport function useBoardColumn<TColumn = unknown>(): TColumn | undefined {\n const value = useBoardColumnContext(BOARD_COLUMN_CONTEXT_NAME);\n return value?.column as TColumn | undefined;\n}\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Atom } from '@effect-atom/atom-react';\nimport { createContext } from '@radix-ui/react-context';\n\nimport { type GetId } from '@dxos/react-ui-dnd';\n\n// Kept out of `Board.tsx`: react-refresh only fast-refreshes a module whose exports are all\n// components, so the model, context and hook exported beside them force a full page reload on every edit.\n\nexport interface BoardModel<TColumn = any, TItem = any> {\n getColumnId: GetId<TColumn>;\n getItemId: GetId<TItem>;\n isColumn: (obj: unknown) => obj is TColumn;\n isItem: (obj: unknown) => obj is TItem;\n columns: Atom.Atom<readonly TColumn[] | TColumn[]>;\n items: (column: TColumn) => Atom.Atom<TItem[]>;\n getColumns: () => TColumn[];\n getItems: (column: TColumn) => TItem[];\n onColumnCreate?: () => Promise<TColumn>;\n onColumnDelete?: (column: TColumn) => void;\n onItemCreate?: (column: TColumn) => Promise<TItem>;\n onItemDelete?: (column: TColumn, item: TItem) => void;\n}\n\n//\n// Context\n//\n\nexport const BOARD_NAME = 'Board';\n\nexport type BoardContextValue<TColumn = any, TItem = any> = {\n model: BoardModel<TColumn, TItem>;\n};\n\nexport const [BoardContextProvider, useBoardContext] = createContext<BoardContextValue>(BOARD_NAME);\n\n/** Hook to read the board model from context (e.g. in custom column tiles). Pass TColumn and TItem for typed model. */\nexport function useBoard<TColumn = any, TItem = any>(displayName?: string): BoardContextValue<TColumn, TItem> {\n return useBoardContext(displayName ?? BOARD_NAME) as BoardContextValue<TColumn, TItem>;\n}\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type FC, type ReactNode, forwardRef, useMemo, useRef } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport { mx } from '@dxos/ui-theme';\n\nimport { useMosaicContainer } from '../components';\n\nexport type UseContainerDebug = [FC<ThemedClassName>, (() => ReactNode) | undefined];\n\n/**\n * Hook that returns a component to be rendered in the container's viewport (within the context),\n * and a component that creates a portal in the container's debug area.\n */\nexport const useContainerDebug = (debug?: boolean): UseContainerDebug => {\n const debugRef = useRef<HTMLDivElement | null>(null);\n return useMemo(() => {\n if (!debug) {\n return [() => null, undefined];\n }\n\n return [\n ({ classNames }) => <div className={mx('overflow-hidden', classNames)} ref={debugRef} />,\n () => debugRef.current && createPortal(<ContainerInfo />, debugRef.current),\n ];\n }, [debug, debugRef]);\n};\n\nconst CONTAINER_INFO_NAME = 'ContainerInfo';\n\nconst ContainerInfo = forwardRef<HTMLDivElement, ThemedClassName>(({ classNames }, forwardedRef) => {\n const { id, state, activeLocation, scrolling } = useMosaicContainer(CONTAINER_INFO_NAME);\n const counter = useRef(0);\n return (\n <JsonHighlighter\n data={{ id, activeLocation, scrolling, state, count: counter.current++ }}\n classNames={mx('text-xs', classNames)}\n ref={forwardedRef}\n />\n );\n});\n\nContainerInfo.displayName = CONTAINER_INFO_NAME;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useMemo } from 'react';\n\nimport { type Obj } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { type DndContainerHandler, type GetId } from '@dxos/react-ui-dnd';\nimport { arrayMove } from '@dxos/util';\n\nexport type UseEventHandlerProps<TItem = any, TObject extends Obj.Unknown = Obj.Unknown> = Pick<\n DndContainerHandler<TItem>,\n 'id' | 'canDrop'\n> & {\n /**\n * The items to manage.\n */\n items: TItem[];\n\n /**\n * ID getter.\n */\n getId: GetId<TItem>;\n\n /**\n * Extracts the object from an item.\n */\n get: (item: TItem) => TObject;\n\n /**\n * Creates a new item from the dragged object.\n */\n make: (object: TObject) => TItem;\n\n /**\n * Optional change callback for wrapping mutations in Obj.update style.\n * When provided, all array mutations will be wrapped in this callback.\n * When not provided, mutations happen directly on the items array.\n */\n onChange?: (mutator: (items: TItem[]) => void) => void;\n};\n\n/**\n * Returns a handler for the given items.\n * NOTE: This supports arrays of objects, or arrays of refs to objects.\n */\nexport const useEventHandlerAdapter = <TItem = any, TObject extends Obj.Unknown = Obj.Unknown>({\n items,\n getId,\n get,\n make,\n onChange,\n ...props\n}: UseEventHandlerProps<TItem, TObject>): DndContainerHandler<TItem> => {\n return useMemo<DndContainerHandler<TItem>>(\n () => ({\n ...props,\n onTake: ({ source }, cb) => {\n log.info('onTake', { source });\n const mutate = (items: TItem[]) => {\n const from = items.findIndex((item) => getId(item) === source.id);\n if (from !== -1) {\n items.splice(from, 1);\n }\n };\n\n if (onChange) {\n onChange(mutate);\n } else {\n mutate(items);\n }\n\n void cb(source.data);\n },\n onDrop: ({ source, target }) => {\n log.info('onDrop', { source, target });\n\n const mutate = (items: TItem[]) => {\n const to =\n target?.type === 'tile' || target?.type === 'placeholder'\n ? target.location\n : target?.type === 'container'\n ? items.length\n : -1;\n const from = items.findIndex((item) => getId(item) === source.id);\n const insertIndex = typeof to === 'number' && to >= 0 ? Math.floor(to) : -1;\n if (insertIndex !== -1) {\n if (from !== -1) {\n arrayMove(items, from, insertIndex);\n } else {\n // TODO(burdon): This should be the responsibility of the source container.\n items.splice(insertIndex, 0, make(get(source.data)));\n }\n }\n };\n\n if (onChange) {\n onChange(mutate);\n } else {\n mutate(items);\n }\n },\n }),\n [items, onChange],\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Obj } from '@dxos/echo';\nimport { type DndContainerHandler, type GetId } from '@dxos/react-ui-dnd';\n\nimport { useEventHandlerAdapter } from './useEventHandlerAdapter';\n\n/**\n * Minimal model shape needed to build the default column handler.\n */\nexport type DefaultColumnEventHandlerModel<TColumn = unknown> = {\n getColumnId: GetId<TColumn>;\n isColumn: (obj: unknown) => obj is TColumn;\n};\n\n/**\n * Returns the default column drag/drop handler (no persistence).\n * Use this when no custom eventHandler is passed to Board.Content.\n */\nexport const useDefaultColumnEventHandler = <TColumn extends Obj.Unknown = Obj.Unknown>(\n id: string,\n model: DefaultColumnEventHandlerModel<TColumn>,\n items: TColumn[],\n): DndContainerHandler<TColumn> =>\n useEventHandlerAdapter<TColumn, TColumn>({\n id,\n items,\n getId: model.getColumnId,\n get: (data) => data,\n make: (object) => object,\n canDrop: ({ source }) => model.isColumn(source.data),\n });\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension, StateEffect, StateField } from '@codemirror/state';\nimport { Decoration, type DecorationSet, EditorView, ViewPlugin, WidgetType } from '@codemirror/view';\n\nexport type DropHandlerEvent = {\n text: string;\n url: string;\n};\n\nexport type DropHandlerOptions = {\n onDrop?: (view: EditorView, pos: number, event: DropHandlerEvent) => void;\n};\n\nexport type DropHandler = {\n extension: Extension;\n update: (position: { x: number; y: number } | null) => void;\n cancel: () => void;\n drop: (event: DropHandlerEvent) => void;\n};\n\nexport const dropHandler = ({ onDrop = handleDrop }: DropHandlerOptions = {}): DropHandler => {\n const views = new Set<EditorView>();\n let state: { view: EditorView; pos: number } | null = null;\n\n const reset = () => {\n views.forEach((view) => view.dispatch({ effects: setDrop.of(null) }));\n state = null;\n };\n\n const extension: Extension = [\n dropField,\n ViewPlugin.fromClass(\n class {\n constructor(readonly _view: EditorView) {\n views.add(_view);\n }\n\n destroy() {\n views.delete(this._view);\n }\n },\n ),\n ];\n\n return {\n extension,\n update: (position: { x: number; y: number } | null) => {\n if (!position) {\n reset();\n return;\n }\n\n views.forEach((view) => {\n const rect = view.dom.getBoundingClientRect();\n if (\n position.x >= rect.left &&\n position.x <= rect.right &&\n position.y >= rect.top &&\n position.y <= rect.bottom\n ) {\n let pos = view.posAtCoords(position);\n if (pos !== null) {\n const word = view.state.wordAt(pos);\n if (word) {\n const startDist = Math.abs(pos - word.from);\n const endDist = Math.abs(pos - word.to);\n pos = startDist < endDist ? word.from : word.to;\n }\n\n view.dispatch({ effects: setDrop.of(pos) });\n state = { view, pos };\n return;\n }\n }\n\n view.dispatch({ effects: setDrop.of(null) });\n });\n },\n cancel: () => {\n reset();\n },\n drop: ({ text, url }) => {\n if (state) {\n onDrop(state.view, state.pos, { text, url });\n }\n\n reset();\n },\n } satisfies DropHandler;\n};\n\nconst handleDrop = (view: EditorView, pos: number, event: DropHandlerEvent) => {\n const line = view.state.doc.lineAt(pos);\n if (line.text.trim() === '') {\n view.dispatch({\n changes: { from: pos, insert: `\\n\\n` },\n effects: setDrop.of(null),\n });\n } else {\n view.dispatch({\n changes: { from: pos, insert: ` [${event.text}](${event.url})` },\n effects: setDrop.of(null),\n });\n }\n};\n\nconst setDrop = StateEffect.define<number | null>();\n\nconst dropField = StateField.define<DecorationSet>({\n create: () => Decoration.none,\n update: (decorations, tr) => {\n for (const effect of tr.effects) {\n if (effect.is(setDrop)) {\n if (effect.value === null) {\n return Decoration.none;\n }\n return Decoration.set([\n Decoration.widget({\n widget: new (class extends WidgetType {\n toDOM() {\n const dom = document.createElement('span');\n dom.className = 'cm-drop-cursor';\n dom.style.borderLeft = '2px solid var(--color-accent-bg)';\n dom.style.display = 'inline-block';\n dom.style.height = '1em';\n dom.style.verticalAlign = 'middle';\n return dom;\n }\n })(),\n side: 0,\n }).range(effect.value),\n ]);\n }\n }\n return decorations.map(tr.changes);\n },\n provide: (field) => EditorView.decorations.from(field),\n});\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport React, { type ReactElement, type Ref as ReactRef, forwardRef, useMemo, useRef, useState } from 'react';\n\nimport { Obj } from '@dxos/echo';\nimport { Card, Icon, IconButton, Tag, useTranslation } from '@dxos/react-ui';\nimport { Menu, createMenuAction } from '@dxos/react-ui-menu';\nimport { getHashStyles } from '@dxos/ui-theme';\n\nimport { translationKey } from '#translations';\n\nimport { Focus } from '../Focus';\nimport { Mosaic, type MosaicTileProps } from '../Mosaic';\nimport { useBoardColumn } from './BoardColumnContext';\nimport { useBoard } from './BoardContext';\n\nconst BOARD_ITEM_NAME = 'Board.Item';\n\ntype BoardItemProps<TItem extends Obj.Unknown = any> = Pick<\n MosaicTileProps<TItem>,\n 'classNames' | 'location' | 'data' | 'debug' | 'draggable'\n>;\n\nconst BoardItemInner = forwardRef<HTMLDivElement, BoardItemProps>(\n ({ classNames, data, location, debug, draggable }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n const rootRef = useRef<HTMLDivElement>(null);\n const composedRef = useComposedRefs<HTMLDivElement>(rootRef, forwardedRef);\n // Use state (callback ref) so the dragHandle prop updates when the button mounts.\n // Refs don't trigger re-renders, so reading `.current` at render time leaves the prop null.\n const [dragHandle, setDragHandle] = useState<HTMLButtonElement | null>(null);\n\n const { model } = useBoard(BOARD_ITEM_NAME);\n const column = useBoardColumn();\n const items = useMemo(\n () =>\n column != null && model.onItemDelete\n ? [\n createMenuAction('delete-item', () => model.onItemDelete?.(column, data), {\n label: t('delete-menu.label'),\n icon: 'ph--trash--regular',\n }),\n ]\n : [],\n [column, data, model.onItemDelete, t],\n );\n\n if (!data) {\n return null;\n }\n\n const label = Obj.getLabel(data);\n const description = Obj.getDescription(data);\n\n return (\n <Menu.Root>\n <Mosaic.Tile\n ref={rootRef}\n asChild\n draggable={draggable}\n dragHandle={dragHandle}\n id={data.id}\n data={data}\n location={location}\n debug={debug}\n >\n <Focus.Item asChild>\n <Card.Root\n classNames={classNames}\n data-testid='board-item'\n ref={composedRef}\n onClick={(event) => event.currentTarget.focus()}\n >\n <Card.Header>\n <Card.DragHandle ref={setDragHandle} testId='mosaicBoard.cardDragHandle' />\n <Card.Title data-testid='mosaicBoard.cardTitle'>{label}</Card.Title>\n {/* TODO(wittjosiah): Reconcile with Card.Menu. */}\n <Card.Block end>\n <Menu.Trigger asChild disabled={!items?.length}>\n <IconButton\n iconOnly\n variant='ghost'\n icon='ph--dots-three-vertical--regular'\n label={t('action-menu.label')}\n />\n </Menu.Trigger>\n </Card.Block>\n <Menu.Content items={items} />\n </Card.Header>\n {/* TODO(burdon): Replace with surface. */}\n <Card.Row classNames='text-description'>\n <Card.Block>\n <Icon icon='ph--note--regular' />\n </Card.Block>\n <Card.Text>{description}</Card.Text>\n </Card.Row>\n <Card.Row>\n <Card.Block>\n <Icon icon='ph--tag--regular' />\n </Card.Block>\n {label && (\n <div className='shrink-0 flex gap-1 items-center text-xs'>\n <Tag hue={getHashStyles(label).hue}>{label}</Tag>\n </div>\n )}\n </Card.Row>\n </Card.Root>\n </Focus.Item>\n </Mosaic.Tile>\n </Menu.Root>\n );\n },\n);\n\nBoardItemInner.displayName = BOARD_ITEM_NAME;\n\n/**\n * Default board tile.\n */\nconst BoardItem = BoardItemInner as <TItem extends Obj.Unknown = any>(\n props: BoardItemProps<TItem> & { ref?: ReactRef<HTMLDivElement> },\n) => ReactElement;\n\nexport { BoardItem, type BoardItemProps };\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { useAtomValue } from '@effect-atom/atom-react';\nimport React, {\n type PropsWithChildren,\n type ReactElement,\n type Ref as ReactRef,\n forwardRef,\n useMemo,\n useState,\n} from 'react';\n\nimport { Obj, Ref } from '@dxos/echo';\nimport { useObject } from '@dxos/echo-react';\nimport { IconButton, ScrollArea, type ThemedClassName, Toolbar, useTranslation } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { Menu, createMenuAction } from '@dxos/react-ui-menu';\nimport { mx } from '@dxos/ui-theme';\n\nimport { translationKey } from '#translations';\n\nimport { useContainerDebug, useEventHandlerAdapter } from '../../hooks';\nimport { Focus } from '../Focus';\nimport { Mosaic, type MosaicContainerProps, type MosaicStackProps, type MosaicTileProps } from '../Mosaic';\nimport { BoardColumnProvider, useBoardColumn } from './BoardColumnContext';\nimport { useBoard } from './BoardContext';\nimport { BoardItem } from './Item';\n\ntype BoardColumnProps<TColumn = any> = Pick<\n MosaicTileProps<TColumn>,\n 'classNames' | 'location' | 'data' | 'debug' | 'draggable'\n>;\n\n//\n// Column Root\n//\n\nconst BOARD_COLUMN_ROOT_NAME = 'Board.Column.Root';\n\ntype BoardColumnRootProps<TColumn = any> = PropsWithChildren<BoardColumnProps<TColumn>> & {\n // Pass the actual button element (not a ref). Refs don't trigger re-renders, so reading\n // `ref.current` at render time leaves Mosaic.Tile's `dragHandle` prop null forever.\n // Consumers should track this with `useState` and a callback ref on `Board.Column.Header`.\n dragHandle?: HTMLButtonElement | null;\n};\n\nconst BoardColumnRootInner = composable<HTMLDivElement, BoardColumnRootProps>(\n ({ classNames, children, location, data, debug, draggable, dragHandle, ...rest }, forwardedRef) => {\n const { model } = useBoard(BOARD_COLUMN_ROOT_NAME);\n\n return (\n <Mosaic.Tile\n asChild\n location={location}\n id={model.getColumnId(data)}\n data={data}\n debug={debug}\n draggable={draggable}\n dragHandle={dragHandle}\n >\n <Focus.Group\n {...rest}\n data-testid='board-column'\n border\n classNames={mx(\n 'group/column',\n 'h-full w-full md:w-card-default-width snap-center dx-deck-surface',\n 'overflow-hidden',\n classNames,\n )}\n ref={forwardedRef}\n >\n <BoardColumnProvider column={data}>{children}</BoardColumnProvider>\n </Focus.Group>\n </Mosaic.Tile>\n );\n },\n);\n\nBoardColumnRootInner.displayName = BOARD_COLUMN_ROOT_NAME;\n\nconst BoardColumnRoot = BoardColumnRootInner as <TColumn = unknown>(\n props: BoardColumnRootProps<TColumn> & { ref?: ReactRef<HTMLDivElement> },\n) => ReactElement;\n\n//\n// Column Header\n//\n\nconst BOARD_COLUMN_HEADER_NAME = 'Board.Column.Header';\n\ntype BoardColumnHeaderProps = { label: string; dragHandleRef: ReactRef<HTMLButtonElement> };\n\nconst BoardColumnHeader = composable<HTMLDivElement, BoardColumnHeaderProps>(\n ({ label, dragHandleRef, ...props }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n const { model } = useBoard(BOARD_COLUMN_HEADER_NAME);\n const column = useBoardColumn();\n const columnMenuItems = useMemo(\n () =>\n column != null && model.onColumnDelete\n ? [\n createMenuAction('delete-column', () => model.onColumnDelete?.(column), {\n label: t('delete-menu.label'),\n icon: 'ph--trash--regular',\n }),\n ]\n : [],\n [column, model.onColumnDelete, t],\n );\n\n return (\n <Menu.Root>\n {/* TODO(burdon): Use Card.Header. */}\n <Toolbar.Root\n {...composableProps(props, { classNames: 'gap-0' })}\n data-testid='board-column-header'\n ref={forwardedRef}\n >\n <Toolbar.DragHandle ref={dragHandleRef} testId='mosaicBoard.columnDragHandle' />\n <Toolbar.Text classNames='grow px-0' data-testid='mosaicBoard.columnTitle'>\n {label}\n </Toolbar.Text>\n {/* TODO(wittjosiah): Reconcile with Card.Menu. */}\n <Menu.Trigger asChild disabled={!columnMenuItems?.length}>\n <Toolbar.IconButton\n iconOnly\n variant='ghost'\n icon='ph--dots-three-vertical--regular'\n label={t('action-menu.label')}\n />\n </Menu.Trigger>\n <Menu.Content items={columnMenuItems} />\n </Toolbar.Root>\n </Menu.Root>\n );\n },\n);\n\nBoardColumnHeader.displayName = BOARD_COLUMN_HEADER_NAME;\n\n//\n// Column Body\n//\n\nconst BOARD_COLUMN_BODY_NAME = 'Board.Column.Body';\n\ntype BoardColumnBodyProps = Pick<BoardColumnProps, 'data'> &\n Pick<MosaicContainerProps, 'eventHandler' | 'debug'> & {\n Tile?: MosaicStackProps<Obj.Unknown>['Tile'];\n };\n\nconst BoardColumnBody = composable<HTMLDivElement, BoardColumnBodyProps>(\n ({ data, eventHandler, Tile = BoardItem, debug, ...props }, forwardedRef) => {\n const { model } = useBoard(BOARD_COLUMN_BODY_NAME);\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n const items = useAtomValue(model.items(data));\n\n return (\n <Mosaic.Container\n {...composableProps(props)}\n asChild\n withFocus\n orientation='vertical'\n autoScroll={viewport}\n eventHandler={eventHandler}\n debug={debug}\n ref={forwardedRef}\n >\n <ScrollArea.Root orientation='vertical' thin centered padding>\n <ScrollArea.Viewport classNames='snap-y md:snap-none' ref={setViewport}>\n <Mosaic.Stack items={items} getId={model.getItemId} Tile={Tile} />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Mosaic.Container>\n );\n },\n);\n\nBoardColumnBody.displayName = BOARD_COLUMN_BODY_NAME;\n\n//\n// Column Footer\n//\n\nconst BOARD_COLUMN_FOOTER_NAME = 'Board.Column.Footer';\n\ntype BoardColumnFooterProps = ThemedClassName & {\n data?: any;\n onAdd?: () => void;\n};\n\nconst BoardColumnFooter = forwardRef<HTMLDivElement, BoardColumnFooterProps>(\n ({ classNames, data, onAdd }, forwardedRef) => {\n const { t } = useTranslation(translationKey);\n const { model } = useBoard(BOARD_COLUMN_FOOTER_NAME);\n\n const handleAdd = onAdd ?? (model.onItemCreate && data ? () => void model.onItemCreate?.(data) : undefined);\n\n return (\n <Toolbar.Root classNames={mx('rounded-b-sm border-t border-separator', classNames)} ref={forwardedRef}>\n {handleAdd && (\n <IconButton\n data-testid='board-column-add-item'\n classNames='group-hover/column:opacity-100 md:opacity-0 transition transition-opacity duration-500'\n variant='ghost'\n icon='ph--plus--regular'\n iconOnly\n label={t('add-item.label')}\n onClick={handleAdd}\n />\n )}\n </Toolbar.Root>\n );\n },\n);\n\nBoardColumnFooter.displayName = BOARD_COLUMN_FOOTER_NAME;\n\n//\n// DefaultBoardColumn\n//\n\nconst BOARD_DEFAULT_COLUMN_NAME = 'Board.DefaultColumn';\n\ntype DefaultBoardColumnProps = BoardColumnProps & Pick<BoardColumnBodyProps, 'Tile'>;\n\nconst DefaultBoardColumn = forwardRef<HTMLDivElement, DefaultBoardColumnProps>(\n ({ classNames, location, data, debug, draggable, Tile = BoardItem }, forwardedRef) => {\n const { model } = useBoard(BOARD_DEFAULT_COLUMN_NAME);\n const [DebugInfo, debugHandler] = useContainerDebug(debug);\n const [dragHandle, setDragHandle] = useState<HTMLButtonElement | null>(null);\n const [column, updateColumn] = useObject(data);\n\n const eventHandler = useEventHandlerAdapter<Ref.Unknown>({\n id: model.getColumnId(data),\n items: column?.items ?? [],\n getId: (ref) => ref.target?.id ?? ref.uri,\n get: (refOrObj) => (Ref.isRef(refOrObj) ? refOrObj.target! : refOrObj),\n make: (object) => Ref.make(object),\n canDrop: ({ source }) => {\n const item = Ref.isRef(source.data) ? source.data.target : source.data;\n return item != null && Obj.isObject(item) && model.isItem(item);\n },\n onChange: (mutator) => updateColumn((col) => mutator(col.items)),\n });\n\n return (\n <BoardColumnRootInner\n classNames={mx(\n 'group/column grid',\n debug\n ? 'grid-rows-[var(--dx-rail-action)_1fr_20rem]'\n : 'grid-rows-[var(--dx-rail-action)_1fr_var(--dx-rail-action)]',\n classNames,\n )}\n location={location}\n data={data}\n draggable={draggable}\n dragHandle={dragHandle}\n ref={forwardedRef}\n >\n <BoardColumnHeader label={Obj.getLabel(data) ?? data.id} dragHandleRef={setDragHandle} />\n <BoardColumnBody data={data} eventHandler={eventHandler} debug={debugHandler} Tile={Tile} />\n <div className='flex flex-col col-span-full'>\n <BoardColumnFooter data={data} />\n <DebugInfo />\n </div>\n </BoardColumnRootInner>\n );\n },\n);\n\nDefaultBoardColumn.displayName = BOARD_DEFAULT_COLUMN_NAME;\n\n//\n// BoardColumn\n//\n\nexport const BoardColumn = {\n Root: BoardColumnRoot,\n Header: BoardColumnHeader,\n Body: BoardColumnBody,\n Footer: BoardColumnFooter,\n};\n\nexport { DefaultBoardColumn };\n\nexport { type BoardColumnProps };\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { useAtomValue } from '@effect-atom/atom-react';\nimport React, {\n type PropsWithChildren,\n type ReactElement,\n type Ref as ReactRef,\n forwardRef,\n useRef,\n useState,\n} from 'react';\n\nimport { ScrollArea, type ThemedClassName } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { type DndContainerHandler, useDndRootContext } from '@dxos/react-ui-dnd';\nimport { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport { mx } from '@dxos/ui-theme';\n\nimport { useContainerDebug } from '../../hooks';\nimport { Focus } from '../Focus';\nimport { Mosaic, type MosaicPlaceholderProps, type MosaicStackProps, mosaicStyles } from '../Mosaic';\nimport { BoardContextProvider, type BoardContextValue, useBoardContext } from './BoardContext';\nimport { BoardColumn, type BoardColumnProps, DefaultBoardColumn } from './Column';\nimport { BoardItem, type BoardItemProps } from './Item';\n\n//\n// Root\n//\n\nconst BOARD_ROOT_NAME = 'Board.Root';\n\ntype BoardRootProps<TColumn = any, TItem = any> = PropsWithChildren<BoardContextValue<TColumn, TItem>>;\n\nconst BoardRootInner = ({ model, children }: BoardRootProps) => {\n return <BoardContextProvider model={model}>{children}</BoardContextProvider>;\n};\n\nBoardRootInner.displayName = BOARD_ROOT_NAME;\n\nconst BoardRoot = BoardRootInner as <TColumn = any, TItem = any>(props: BoardRootProps<TColumn, TItem>) => ReactElement;\n\n//\n// Content\n//\n\nconst BOARD_CONTENT_NAME = 'Board.Content';\n\ntype BoardContentProps<TColumn = any> = ThemedClassName<{\n debug?: boolean;\n eventHandler?: DndContainerHandler<TColumn>;\n Tile?: MosaicStackProps<TColumn>['Tile'];\n}>;\n\nconst BoardContentInner = composable<HTMLDivElement, BoardContentProps>(\n ({ debug, eventHandler, Tile = DefaultBoardColumn, ...props }, forwardedRef) => {\n const { model } = useBoardContext(BOARD_CONTENT_NAME);\n const [DebugInfo, debugHandler] = useContainerDebug(debug);\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n\n const items = useAtomValue(model.columns);\n\n return (\n <div {...composableProps(props, { classNames: 'dx-container' })} ref={forwardedRef}>\n <Focus.Group asChild orientation='horizontal'>\n <Mosaic.Container\n asChild\n withFocus\n orientation='horizontal'\n autoScroll={viewport}\n eventHandler={eventHandler}\n debug={debugHandler}\n placeholderDebug={debug}\n >\n <ScrollArea.Root orientation='horizontal' centered padding>\n <ScrollArea.Viewport classNames='snap-mandatory snap-x md:snap-none' ref={setViewport}>\n <Mosaic.Stack items={items} getId={model.getColumnId} Tile={Tile} debug={debug} />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Mosaic.Container>\n </Focus.Group>\n <DebugInfo />\n </div>\n );\n },\n);\n\nBoardContentInner.displayName = BOARD_CONTENT_NAME;\n\nconst BoardContent = BoardContentInner as <TColumn = any>(\n props: BoardContentProps<TColumn> & { ref?: ReactRef<HTMLDivElement> },\n) => ReactElement;\n\n//\n// Placeholder\n//\n\nconst BOARD_PLACEHOLDER_NAME = 'Board.Placeholder';\n\nconst BoardPlaceholder = (props: MosaicPlaceholderProps<number>) => {\n return (\n <Mosaic.Placeholder {...props} classNames={mosaicStyles.placeholder.root}>\n <div\n className={mx('flex h-full border border-dashed border-separator rounded-xs', mosaicStyles.placeholder.content)}\n />\n </Mosaic.Placeholder>\n );\n};\n\nBoardPlaceholder.displayName = BOARD_PLACEHOLDER_NAME;\n\n//\n// Debug\n//\n\nconst BOARD_DEBUG_NAME = 'Board.Debug';\n\nexport const BoardDebug = forwardRef<HTMLDivElement, ThemedClassName>(({ classNames }, forwardedRef) => {\n const { containers, dragging } = useDndRootContext(BOARD_DEBUG_NAME);\n const counter = useRef(0);\n return (\n <JsonHighlighter\n data={{ containers, dragging, count: counter.current++ }}\n classNames={mx('text-xs', classNames)}\n ref={forwardedRef}\n />\n );\n});\n\nBoardDebug.displayName = BOARD_DEBUG_NAME;\n\n//\n// Board\n//\n\nexport const Board = {\n Root: BoardRoot,\n Content: BoardContent,\n Column: BoardColumn,\n Item: BoardItem,\n Placeholder: BoardPlaceholder,\n Debug: BoardDebug,\n};\n\nexport type { BoardColumnProps, BoardContentProps, BoardItemProps, BoardRootProps };\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { type KeyboardEvent, forwardRef, useCallback, useMemo, useState } from 'react';\n\nimport { Card, ScrollArea } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { type SearchResult } from '@dxos/react-ui-search';\n\nimport { Focus, Mosaic, type MosaicTileProps, useMosaicContainer } from '../..';\n\nexport type SearchStackAction = {\n type: 'select';\n resultId: string;\n};\n\nexport type SearchStackActionHandler = (action: SearchStackAction) => void;\n\n//\n// SearchStack\n//\n\nexport type SearchStackProps = {\n id: string;\n results?: SearchResult[];\n currentId?: string;\n onAction?: SearchStackActionHandler;\n};\n\n/**\n * Card-based search result stack component using mosaic layout.\n */\nexport const SearchStack = composable<HTMLDivElement, SearchStackProps>(\n ({ results = [], currentId, onAction, ...props }, forwardedRef) => {\n const [viewport, setViewport] = useState<HTMLElement | null>(null);\n const items = useMemo(() => results.map((result) => ({ result, onAction })), [results, onAction]);\n\n const handleCurrentChange = useCallback(\n (id: string | undefined) => {\n if (id) {\n onAction?.({ type: 'select', resultId: id });\n }\n },\n [onAction],\n );\n\n const handleKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n (document.activeElement as HTMLElement | null)?.click();\n }\n }, []);\n\n return (\n <Focus.Group asChild {...composableProps(props)} onKeyDown={handleKeyDown} ref={forwardedRef}>\n <Mosaic.Container asChild withFocus currentId={currentId} onCurrentChange={handleCurrentChange}>\n <ScrollArea.Root orientation='vertical' padding centered thin>\n <ScrollArea.Viewport ref={setViewport}>\n <Mosaic.VirtualStack\n Tile={SearchTile}\n classNames='my-2'\n gap={8}\n items={items}\n draggable={false}\n getId={(item) => item.result.id}\n getScrollElement={() => viewport}\n estimateSize={() => 100}\n />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Mosaic.Container>\n </Focus.Group>\n );\n },\n);\n\nSearchStack.displayName = 'SearchStack';\n\n//\n// SearchTile\n//\n\ntype SearchTileData = {\n result: SearchResult;\n onAction?: SearchStackActionHandler;\n};\n\ntype SearchTileProps = Pick<MosaicTileProps<SearchTileData>, 'location' | 'data' | 'current'>;\n\n/**\n * Default search result tile with a simple Card header.\n */\nconst SearchTile = forwardRef<HTMLDivElement, SearchTileProps>(({ data, location, current }, forwardedRef) => {\n const { result } = data;\n const { setCurrentId } = useMosaicContainer('SearchTile');\n\n const handleCurrentChange = useCallback(() => {\n setCurrentId(result.id);\n }, [result.id, setCurrentId]);\n\n // Navigation / current pattern: clicking a result navigates to its\n // detail. `dx-current` pairs with the `aria-current` attribute that\n // `Mosaic.Tile` now sets from the `current` prop. `dx-selected`\n // (master/detail option pattern) would be the wrong grammar here.\n // See `ui-theme/src/css/components/selected.md`.\n return (\n <Mosaic.Tile\n asChild\n classNames='dx-hover dx-current'\n id={result.id}\n data={data}\n location={location}\n current={current}\n >\n <Focus.Item asChild current={current} onCurrentChange={handleCurrentChange}>\n <Card.Root fullWidth ref={forwardedRef}>\n <Card.Header>\n <Card.Block />\n <Card.Title>{result.label}</Card.Title>\n </Card.Header>\n {result.snippet && (\n <Card.Body>\n <Card.Row>\n <Card.Text variant='description'>{result.snippet}</Card.Text>\n </Card.Row>\n </Card.Body>\n )}\n </Card.Root>\n </Focus.Item>\n </Mosaic.Tile>\n );\n});\n\nSearchTile.displayName = 'SearchTile';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { expect } from "@playwright/test";
|
|
2
|
+
//#region src/playwright/board-manager.ts
|
|
3
|
+
var BoardManager = class {
|
|
4
|
+
locator;
|
|
5
|
+
_page;
|
|
6
|
+
constructor(locator) {
|
|
7
|
+
this.locator = locator;
|
|
8
|
+
this._page = locator.page();
|
|
9
|
+
}
|
|
10
|
+
columns() {
|
|
11
|
+
return this.locator.getByTestId("board-column");
|
|
12
|
+
}
|
|
13
|
+
column(index) {
|
|
14
|
+
return new ColumnManager(this.locator.getByTestId("board-column").nth(index));
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var ColumnManager = class {
|
|
18
|
+
locator;
|
|
19
|
+
_page;
|
|
20
|
+
constructor(locator) {
|
|
21
|
+
this.locator = locator;
|
|
22
|
+
this._page = locator.page();
|
|
23
|
+
}
|
|
24
|
+
items() {
|
|
25
|
+
return this.locator.getByTestId("board-item");
|
|
26
|
+
}
|
|
27
|
+
item(index) {
|
|
28
|
+
return new ItemManager(this.locator.getByTestId("board-item").nth(index));
|
|
29
|
+
}
|
|
30
|
+
async addItem() {
|
|
31
|
+
await this.locator.getByTestId("board-column-add-item").click();
|
|
32
|
+
}
|
|
33
|
+
header() {
|
|
34
|
+
return this.locator.getByTestId("board-column-header");
|
|
35
|
+
}
|
|
36
|
+
title() {
|
|
37
|
+
return this.locator.getByTestId("mosaicBoard.columnTitle");
|
|
38
|
+
}
|
|
39
|
+
async dragTo(target, offset = {
|
|
40
|
+
x: 0,
|
|
41
|
+
y: 0
|
|
42
|
+
}) {
|
|
43
|
+
const handle = this.header().getByTestId("mosaicBoard.columnDragHandle");
|
|
44
|
+
const handleBox = await handle.boundingBox();
|
|
45
|
+
if (!handleBox) return;
|
|
46
|
+
await handle.hover();
|
|
47
|
+
await this._page.mouse.down();
|
|
48
|
+
await this._page.mouse.move(handleBox.x + handleBox.width / 2 + 1, handleBox.y + handleBox.height / 2, { steps: 1 });
|
|
49
|
+
await this._page.waitForTimeout(200);
|
|
50
|
+
const box = await target.boundingBox();
|
|
51
|
+
if (box) {
|
|
52
|
+
await this._page.mouse.move(offset.x + box.x + box.width / 2, offset.y + box.y + box.height / 2, { steps: 4 });
|
|
53
|
+
await this._page.waitForTimeout(100);
|
|
54
|
+
await this._page.mouse.up();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var ItemManager = class {
|
|
59
|
+
locator;
|
|
60
|
+
_page;
|
|
61
|
+
constructor(locator) {
|
|
62
|
+
this.locator = locator;
|
|
63
|
+
this._page = locator.page();
|
|
64
|
+
}
|
|
65
|
+
title() {
|
|
66
|
+
return this.locator.getByTestId("mosaicBoard.cardTitle");
|
|
67
|
+
}
|
|
68
|
+
async dragTo(target, offset = {
|
|
69
|
+
x: 0,
|
|
70
|
+
y: 0
|
|
71
|
+
}, edge) {
|
|
72
|
+
const handle = this.locator.getByTestId("mosaicBoard.cardDragHandle");
|
|
73
|
+
const handleBox = await handle.boundingBox();
|
|
74
|
+
if (!handleBox) return;
|
|
75
|
+
const targetHandle = await target.elementHandle();
|
|
76
|
+
const box = targetHandle ? await targetHandle.boundingBox() : null;
|
|
77
|
+
if (!targetHandle || !box) return;
|
|
78
|
+
const sourceHandle = await this.locator.elementHandle();
|
|
79
|
+
await handle.hover();
|
|
80
|
+
await this._page.mouse.down();
|
|
81
|
+
await this._page.waitForTimeout(100);
|
|
82
|
+
if (edge) {
|
|
83
|
+
await this._page.mouse.move(handleBox.x + handleBox.width / 2 + 1, handleBox.y + handleBox.height / 2, { steps: 1 });
|
|
84
|
+
await this._page.mouse.move(box.x + box.width / 2, box.y + box.height / 2, { steps: 4 });
|
|
85
|
+
await expect.poll(() => this._page.locator("[data-mosaic-container-state=\"active\"]").count(), { timeout: 2e3 }).toBeGreaterThan(0);
|
|
86
|
+
if (sourceHandle) await this._page.waitForFunction((el) => !el || !el.isConnected, sourceHandle, { timeout: 2e3 });
|
|
87
|
+
const placeholderHandle = await this._adjacentPlaceholder(targetHandle, edge);
|
|
88
|
+
if (placeholderHandle) {
|
|
89
|
+
const phBox = await placeholderHandle.boundingBox();
|
|
90
|
+
if (phBox) {
|
|
91
|
+
const aimX = phBox.x + phBox.width / 2;
|
|
92
|
+
const aimY = phBox.y + Math.max(phBox.height / 2, 1);
|
|
93
|
+
await this._page.mouse.move(aimX, aimY, { steps: 4 });
|
|
94
|
+
const isActive = () => placeholderHandle.evaluate((el) => el.getAttribute("data-mosaic-placeholder-state") === "active");
|
|
95
|
+
if (!await isActive()) {
|
|
96
|
+
const start = Date.now();
|
|
97
|
+
let nudge = 0;
|
|
98
|
+
while (Date.now() - start < 3e3) {
|
|
99
|
+
await this._page.waitForTimeout(100);
|
|
100
|
+
nudge = (nudge + 1) % 4;
|
|
101
|
+
const dx = nudge === 0 || nudge === 2 ? 1 : -1;
|
|
102
|
+
const dy = nudge === 1 || nudge === 2 ? 1 : -1;
|
|
103
|
+
await this._page.mouse.move(aimX + dx, aimY + dy, { steps: 1 });
|
|
104
|
+
if (await isActive()) break;
|
|
105
|
+
}
|
|
106
|
+
await expect.poll(() => placeholderHandle.evaluate((el) => el.getAttribute("data-mosaic-placeholder-state")), { timeout: 1e3 }).toBe("active");
|
|
107
|
+
}
|
|
108
|
+
const expanded = await placeholderHandle.boundingBox();
|
|
109
|
+
if (expanded) await this._page.mouse.move(expanded.x + expanded.width / 2, expanded.y + expanded.height / 2, { steps: 2 });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
await this._page.mouse.move(offset.x + box.x + box.width / 2, offset.y + box.y + box.height / 2, { steps: 4 });
|
|
114
|
+
await this._page.waitForTimeout(100);
|
|
115
|
+
}
|
|
116
|
+
await this._page.mouse.up();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Find the placeholder element adjacent to `target` on the requested
|
|
120
|
+
* side via DOM walk. Returns `null` if the target has no matching
|
|
121
|
+
* sibling (e.g. when the caller passes a non-tile target).
|
|
122
|
+
*/
|
|
123
|
+
async _adjacentPlaceholder(targetHandle, edge) {
|
|
124
|
+
const before = edge === "top" || edge === "left";
|
|
125
|
+
const handle = (await targetHandle.evaluateHandle((el, beforeArg) => {
|
|
126
|
+
let sibling = beforeArg ? el.previousElementSibling : el.nextElementSibling;
|
|
127
|
+
while (sibling && !sibling.hasAttribute("data-mosaic-placeholder-location")) sibling = beforeArg ? sibling.previousElementSibling : sibling.nextElementSibling;
|
|
128
|
+
return sibling;
|
|
129
|
+
}, before)).asElement();
|
|
130
|
+
if (!handle) return null;
|
|
131
|
+
return await handle.evaluate((el) => el !== null) ? handle : null;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Drag this item to a column's scroll bottom, using auto-scroll when needed,
|
|
135
|
+
* then drop on the target item.
|
|
136
|
+
*
|
|
137
|
+
* When the target is already visible in the viewport (no scrolling needed), the
|
|
138
|
+
* item is dragged directly to the target. When the target is below the viewport,
|
|
139
|
+
* the mouse is held near the footer to trigger pragmatic auto-scroll until the
|
|
140
|
+
* target scrolls into view.
|
|
141
|
+
*
|
|
142
|
+
* @param holdTarget - The footer element; mouse is held ~20px above it to trigger auto-scroll.
|
|
143
|
+
* @param dropTarget - The element to drop on.
|
|
144
|
+
* @param dropOffset - Offset from the drop target center.
|
|
145
|
+
*/
|
|
146
|
+
async dragToEndWithAutoScroll(holdTarget, dropTarget, dropOffset = {
|
|
147
|
+
x: 0,
|
|
148
|
+
y: 0
|
|
149
|
+
}) {
|
|
150
|
+
const handle = this.locator.getByTestId("mosaicBoard.cardDragHandle");
|
|
151
|
+
const holdBox = await holdTarget.boundingBox();
|
|
152
|
+
if (!holdBox) return;
|
|
153
|
+
const holdX = holdBox.x + holdBox.width / 2;
|
|
154
|
+
const holdY = holdBox.y - 20;
|
|
155
|
+
const preDropBox = await dropTarget.boundingBox();
|
|
156
|
+
const needsScroll = !preDropBox || preDropBox.y >= holdBox.y;
|
|
157
|
+
await handle.hover();
|
|
158
|
+
await this._page.mouse.down();
|
|
159
|
+
await this._page.waitForTimeout(100);
|
|
160
|
+
if (!needsScroll) {
|
|
161
|
+
await this._page.mouse.move(holdX, holdY, { steps: 4 });
|
|
162
|
+
const dropBox = await dropTarget.boundingBox();
|
|
163
|
+
if (dropBox) {
|
|
164
|
+
const dropX = dropOffset.x + dropBox.x + dropBox.width / 2;
|
|
165
|
+
const dropY = dropOffset.y + dropBox.y + dropBox.height / 2;
|
|
166
|
+
await this._page.mouse.move(dropX, dropY, { steps: 8 });
|
|
167
|
+
await this._page.waitForTimeout(200);
|
|
168
|
+
await this._page.mouse.up();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await this._page.mouse.up();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await this._page.mouse.move(holdX, holdY, { steps: 4 });
|
|
175
|
+
for (let i = 0; i < 40; i++) {
|
|
176
|
+
await this._page.waitForTimeout(200);
|
|
177
|
+
await this._page.mouse.move(holdX + i % 2, holdY, { steps: 1 });
|
|
178
|
+
const dropBox = await dropTarget.boundingBox();
|
|
179
|
+
if (dropBox && dropBox.y + dropBox.height < holdY) {
|
|
180
|
+
const finalBox = await dropTarget.boundingBox();
|
|
181
|
+
if (!finalBox) {
|
|
182
|
+
await this._page.mouse.up();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const dropX = dropOffset.x + finalBox.x + finalBox.width / 2;
|
|
186
|
+
const dropY = dropOffset.y + finalBox.y + finalBox.height / 2;
|
|
187
|
+
await this._page.mouse.move(dropX, dropY, { steps: 8 });
|
|
188
|
+
await dropTarget.waitFor({ state: "visible" });
|
|
189
|
+
await this._page.waitForTimeout(200);
|
|
190
|
+
await this._page.mouse.up();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
await this._page.mouse.up();
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
//#endregion
|
|
198
|
+
export { BoardManager, ColumnManager, ItemManager };
|
|
199
|
+
|
|
200
|
+
//# sourceMappingURL=playwright.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright.mjs","names":[],"sources":["../../src/playwright/board-manager.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Locator, type Page, expect } from '@playwright/test';\n\n/**\n * Edge of the target tile to drop on. Pragmatic-dnd assigns the closest edge\n * based on cursor position; a stale (pre-layout-shift) cursor can land in the\n * wrong half. When `dragTo` is called with an `edge`, the helper waits for the\n * target tile to register the drag, re-measures the target after the\n * placeholder has expanded, repositions the cursor near the requested edge,\n * and confirms via `data-mosaic-tile-edge` before releasing.\n */\nexport type DragEdge = 'top' | 'bottom' | 'left' | 'right';\n\nexport class BoardManager {\n private readonly _page: Page;\n\n constructor(readonly locator: Locator) {\n this._page = locator.page();\n }\n\n columns(): Locator {\n return this.locator.getByTestId('board-column');\n }\n\n column(index: number): ColumnManager {\n return new ColumnManager(this.locator.getByTestId('board-column').nth(index));\n }\n}\n\nexport class ColumnManager {\n private readonly _page: Page;\n\n constructor(readonly locator: Locator) {\n this._page = locator.page();\n }\n\n items(): Locator {\n return this.locator.getByTestId('board-item');\n }\n\n item(index: number): ItemManager {\n return new ItemManager(this.locator.getByTestId('board-item').nth(index));\n }\n\n async addItem(): Promise<void> {\n await this.locator.getByTestId('board-column-add-item').click();\n }\n\n header(): Locator {\n return this.locator.getByTestId('board-column-header');\n }\n\n title(): Locator {\n return this.locator.getByTestId('mosaicBoard.columnTitle');\n }\n\n async dragTo(target: Locator, offset = { x: 0, y: 0 }): Promise<void> {\n const handle = this.header().getByTestId('mosaicBoard.columnDragHandle');\n const handleBox = await handle.boundingBox();\n if (!handleBox) {\n return;\n }\n\n await handle.hover();\n await this._page.mouse.down();\n // Small initial movement to trigger the native drag start.\n await this._page.mouse.move(handleBox.x + handleBox.width / 2 + 1, handleBox.y + handleBox.height / 2, {\n steps: 1,\n });\n // Allow the drag monitor to register and the DOM to settle\n // (the dragged column is removed from visible items, shifting remaining columns).\n await this._page.waitForTimeout(200);\n const box = await target.boundingBox();\n if (box) {\n await this._page.mouse.move(offset.x + box.x + box.width / 2, offset.y + box.y + box.height / 2, { steps: 4 });\n // Allow the drop target to process the hover before releasing.\n await this._page.waitForTimeout(100);\n await this._page.mouse.up();\n }\n }\n}\n\nexport class ItemManager {\n private readonly _page: Page;\n\n constructor(readonly locator: Locator) {\n this._page = locator.page();\n }\n\n title(): Locator {\n return this.locator.getByTestId('mosaicBoard.cardTitle');\n }\n\n async dragTo(target: Locator, offset: { x: number; y: number } = { x: 0, y: 0 }, edge?: DragEdge): Promise<void> {\n const handle = this.locator.getByTestId('mosaicBoard.cardDragHandle');\n const handleBox = await handle.boundingBox();\n if (!handleBox) {\n return;\n }\n\n // Capture stable ElementHandles to source and target before the drag\n // begins. Both `nth(N)` locators shift when `useVisibleItems` filters the\n // source out of its column, so we need raw DOM references that survive\n // the reconciliation.\n const targetHandle = await target.elementHandle();\n const box = targetHandle ? await targetHandle.boundingBox() : null;\n if (!targetHandle || !box) {\n return;\n }\n const sourceHandle = await this.locator.elementHandle();\n\n await handle.hover();\n await this._page.mouse.down();\n // Allow the drag monitor to register the grab before moving.\n await this._page.waitForTimeout(100);\n\n if (edge) {\n // Stage 1: trigger the dragstart. A 1-pixel nudge near the press\n // point primes pragmatic-dnd's HTML5 dragstart, then a long move\n // over the target tile commits the drag past every browser's\n // \"click vs drag\" threshold.\n await this._page.mouse.move(handleBox.x + handleBox.width / 2 + 1, handleBox.y + handleBox.height / 2, {\n steps: 1,\n });\n await this._page.mouse.move(box.x + box.width / 2, box.y + box.height / 2, { steps: 4 });\n\n // Wait for `data-mosaic-container-state=\"active\"` so we know the\n // dragstart has been processed. This alone is *not* enough: pragmatic-\n // dnd's `monitorForElements.onDragStart` (Root.tsx) and the\n // `dropTargetForElements.onDragStart` (Container.tsx) write into\n // independent React state, and only the latter drives the attribute.\n // The former drives `useVisibleItems` filtering, which is what\n // physically reflows the column. So we ALSO wait for the source tile\n // to detach from the DOM — that's the unambiguous signal that the\n // reflow has happened and any cached bbox is stale.\n await expect\n .poll(() => this._page.locator('[data-mosaic-container-state=\"active\"]').count(), { timeout: 2000 })\n .toBeGreaterThan(0);\n if (sourceHandle) {\n await this._page.waitForFunction((el) => !el || !el.isConnected, sourceHandle, { timeout: 2000 });\n }\n\n // Stage 2: walk siblings on the (now reflowed) drag-time DOM and aim\n // at the placeholder representing the requested edge. The Fragment\n // keying on item id keeps the target tile's adjacent placeholder DOM\n // node stable across reconciliation, but its `location` prop and bbox\n // both change once the source is filtered out — measure after the\n // reflow, never before.\n const placeholderHandle = await this._adjacentPlaceholder(targetHandle, edge);\n if (placeholderHandle) {\n const phBox = await placeholderHandle.boundingBox();\n if (phBox) {\n const aimX = phBox.x + phBox.width / 2;\n const aimY = phBox.y + Math.max(phBox.height / 2, 1);\n await this._page.mouse.move(aimX, aimY, { steps: 4 });\n\n // Some browser/CDP combinations need a follow-up nudge to push\n // the dragOver event through — re-aim with a 1px offset and poll.\n const isActive = () =>\n placeholderHandle.evaluate((el) => el.getAttribute('data-mosaic-placeholder-state') === 'active');\n if (!(await isActive())) {\n const start = Date.now();\n let nudge = 0;\n while (Date.now() - start < 3000) {\n await this._page.waitForTimeout(100);\n nudge = (nudge + 1) % 4;\n const dx = nudge === 0 || nudge === 2 ? 1 : -1;\n const dy = nudge === 1 || nudge === 2 ? 1 : -1;\n await this._page.mouse.move(aimX + dx, aimY + dy, { steps: 1 });\n if (await isActive()) {\n break;\n }\n }\n await expect\n .poll(() => placeholderHandle.evaluate((el) => el.getAttribute('data-mosaic-placeholder-state')), {\n timeout: 1000,\n })\n .toBe('active');\n }\n\n // Re-centre on the now-expanded placeholder so the drop lands\n // solidly inside it.\n const expanded = await placeholderHandle.boundingBox();\n if (expanded) {\n await this._page.mouse.move(expanded.x + expanded.width / 2, expanded.y + expanded.height / 2, {\n steps: 2,\n });\n }\n }\n }\n } else {\n // Legacy path: no explicit edge — rely on the offset placement and a\n // small settle delay before releasing.\n await this._page.mouse.move(offset.x + box.x + box.width / 2, offset.y + box.y + box.height / 2, { steps: 4 });\n await this._page.waitForTimeout(100);\n }\n await this._page.mouse.up();\n }\n\n /**\n * Find the placeholder element adjacent to `target` on the requested\n * side via DOM walk. Returns `null` if the target has no matching\n * sibling (e.g. when the caller passes a non-tile target).\n */\n private async _adjacentPlaceholder(\n targetHandle: import('@playwright/test').ElementHandle<Element | SVGElement | HTMLElement>,\n edge: DragEdge,\n ): Promise<import('@playwright/test').ElementHandle<HTMLElement> | null> {\n const before = edge === 'top' || edge === 'left';\n const result = await targetHandle.evaluateHandle((el, beforeArg) => {\n let sibling: Element | null = beforeArg ? el.previousElementSibling : el.nextElementSibling;\n while (sibling && !sibling.hasAttribute('data-mosaic-placeholder-location')) {\n sibling = beforeArg ? sibling.previousElementSibling : sibling.nextElementSibling;\n }\n return sibling as HTMLElement | null;\n }, before);\n const handle = result.asElement() as import('@playwright/test').ElementHandle<HTMLElement> | null;\n if (!handle) {\n return null;\n }\n // `evaluateHandle` returning `null` still produces a non-null JSHandle —\n // verify the underlying element actually exists.\n const exists = await handle.evaluate((el) => el !== null);\n return exists ? handle : null;\n }\n\n /**\n * Drag this item to a column's scroll bottom, using auto-scroll when needed,\n * then drop on the target item.\n *\n * When the target is already visible in the viewport (no scrolling needed), the\n * item is dragged directly to the target. When the target is below the viewport,\n * the mouse is held near the footer to trigger pragmatic auto-scroll until the\n * target scrolls into view.\n *\n * @param holdTarget - The footer element; mouse is held ~20px above it to trigger auto-scroll.\n * @param dropTarget - The element to drop on.\n * @param dropOffset - Offset from the drop target center.\n */\n async dragToEndWithAutoScroll(holdTarget: Locator, dropTarget: Locator, dropOffset = { x: 0, y: 0 }): Promise<void> {\n const handle = this.locator.getByTestId('mosaicBoard.cardDragHandle');\n const holdBox = await holdTarget.boundingBox();\n if (!holdBox) {\n return;\n }\n\n // The hold position is ~20px above the footer to trigger pragmatic auto-scroll.\n const holdX = holdBox.x + holdBox.width / 2;\n const holdY = holdBox.y - 20;\n\n // Check if drop target is already visible before starting the drag.\n // Items may fit in the viewport without scrolling, in which case auto-scroll\n // is not needed and the loop's exit condition would never be satisfied.\n const preDropBox = await dropTarget.boundingBox();\n const needsScroll = !preDropBox || preDropBox.y >= holdBox.y;\n\n await handle.hover();\n await this._page.mouse.down();\n // Allow the drag monitor to register the grab before moving.\n await this._page.waitForTimeout(100);\n\n if (!needsScroll) {\n // Target is already visible — drag directly without auto-scroll.\n await this._page.mouse.move(holdX, holdY, { steps: 4 });\n const dropBox = await dropTarget.boundingBox();\n if (dropBox) {\n const dropX = dropOffset.x + dropBox.x + dropBox.width / 2;\n const dropY = dropOffset.y + dropBox.y + dropBox.height / 2;\n await this._page.mouse.move(dropX, dropY, { steps: 8 });\n await this._page.waitForTimeout(200);\n await this._page.mouse.up();\n return;\n }\n await this._page.mouse.up();\n return;\n }\n\n // Move to hold position above the footer to trigger auto-scroll.\n await this._page.mouse.move(holdX, holdY, { steps: 4 });\n\n // Hold and nudge mouse periodically to keep auto-scroll active until drop target is visible.\n for (let i = 0; i < 40; i++) {\n // Wait between nudges to give auto-scroll time to advance.\n await this._page.waitForTimeout(200);\n // Small nudge to keep drag events firing (auto-scroll stalls without movement).\n await this._page.mouse.move(holdX + (i % 2), holdY, { steps: 1 });\n\n const dropBox = await dropTarget.boundingBox();\n if (dropBox && dropBox.y + dropBox.height < holdY) {\n // Drop target has scrolled into view. Re-read box so we use current position (scroll may have moved it).\n const finalBox = await dropTarget.boundingBox();\n if (!finalBox) {\n await this._page.mouse.up();\n return;\n }\n\n const dropX = dropOffset.x + finalBox.x + finalBox.width / 2;\n const dropY = dropOffset.y + finalBox.y + finalBox.height / 2;\n await this._page.mouse.move(dropX, dropY, { steps: 8 });\n // Let drop target receive dragOver and settle (headless is faster; needs a moment to register).\n await dropTarget.waitFor({ state: 'visible' });\n await this._page.waitForTimeout(200);\n await this._page.mouse.up();\n return;\n }\n }\n\n // Fallback: drop wherever we are.\n await this._page.mouse.up();\n }\n}\n"],"mappings":";;AAgBA,IAAa,eAAb,MAA0B;CAGH;CAFrB;CAEA,YAAY,SAA2B;EAAlB,KAAA,UAAA;EACnB,KAAK,QAAQ,QAAQ,KAAK;CAC5B;CAEA,UAAmB;EACjB,OAAO,KAAK,QAAQ,YAAY,cAAc;CAChD;CAEA,OAAO,OAA8B;EACnC,OAAO,IAAI,cAAc,KAAK,QAAQ,YAAY,cAAc,CAAC,CAAC,IAAI,KAAK,CAAC;CAC9E;AACF;AAEA,IAAa,gBAAb,MAA2B;CAGJ;CAFrB;CAEA,YAAY,SAA2B;EAAlB,KAAA,UAAA;EACnB,KAAK,QAAQ,QAAQ,KAAK;CAC5B;CAEA,QAAiB;EACf,OAAO,KAAK,QAAQ,YAAY,YAAY;CAC9C;CAEA,KAAK,OAA4B;EAC/B,OAAO,IAAI,YAAY,KAAK,QAAQ,YAAY,YAAY,CAAC,CAAC,IAAI,KAAK,CAAC;CAC1E;CAEA,MAAM,UAAyB;EAC7B,MAAM,KAAK,QAAQ,YAAY,uBAAuB,CAAC,CAAC,MAAM;CAChE;CAEA,SAAkB;EAChB,OAAO,KAAK,QAAQ,YAAY,qBAAqB;CACvD;CAEA,QAAiB;EACf,OAAO,KAAK,QAAQ,YAAY,yBAAyB;CAC3D;CAEA,MAAM,OAAO,QAAiB,SAAS;EAAE,GAAG;EAAG,GAAG;CAAE,GAAkB;EACpE,MAAM,SAAS,KAAK,OAAO,CAAC,CAAC,YAAY,8BAA8B;EACvE,MAAM,YAAY,MAAM,OAAO,YAAY;EAC3C,IAAI,CAAC,WACH;EAGF,MAAM,OAAO,MAAM;EACnB,MAAM,KAAK,MAAM,MAAM,KAAK;EAE5B,MAAM,KAAK,MAAM,MAAM,KAAK,UAAU,IAAI,UAAU,QAAQ,IAAI,GAAG,UAAU,IAAI,UAAU,SAAS,GAAG,EACrG,OAAO,EACT,CAAC;EAGD,MAAM,KAAK,MAAM,eAAe,GAAG;EACnC,MAAM,MAAM,MAAM,OAAO,YAAY;EACrC,IAAI,KAAK;GACP,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,QAAQ,GAAG,OAAO,IAAI,IAAI,IAAI,IAAI,SAAS,GAAG,EAAE,OAAO,EAAE,CAAC;GAE7G,MAAM,KAAK,MAAM,eAAe,GAAG;GACnC,MAAM,KAAK,MAAM,MAAM,GAAG;EAC5B;CACF;AACF;AAEA,IAAa,cAAb,MAAyB;CAGF;CAFrB;CAEA,YAAY,SAA2B;EAAlB,KAAA,UAAA;EACnB,KAAK,QAAQ,QAAQ,KAAK;CAC5B;CAEA,QAAiB;EACf,OAAO,KAAK,QAAQ,YAAY,uBAAuB;CACzD;CAEA,MAAM,OAAO,QAAiB,SAAmC;EAAE,GAAG;EAAG,GAAG;CAAE,GAAG,MAAgC;EAC/G,MAAM,SAAS,KAAK,QAAQ,YAAY,4BAA4B;EACpE,MAAM,YAAY,MAAM,OAAO,YAAY;EAC3C,IAAI,CAAC,WACH;EAOF,MAAM,eAAe,MAAM,OAAO,cAAc;EAChD,MAAM,MAAM,eAAe,MAAM,aAAa,YAAY,IAAI;EAC9D,IAAI,CAAC,gBAAgB,CAAC,KACpB;EAEF,MAAM,eAAe,MAAM,KAAK,QAAQ,cAAc;EAEtD,MAAM,OAAO,MAAM;EACnB,MAAM,KAAK,MAAM,MAAM,KAAK;EAE5B,MAAM,KAAK,MAAM,eAAe,GAAG;EAEnC,IAAI,MAAM;GAKR,MAAM,KAAK,MAAM,MAAM,KAAK,UAAU,IAAI,UAAU,QAAQ,IAAI,GAAG,UAAU,IAAI,UAAU,SAAS,GAAG,EACrG,OAAO,EACT,CAAC;GACD,MAAM,KAAK,MAAM,MAAM,KAAK,IAAI,IAAI,IAAI,QAAQ,GAAG,IAAI,IAAI,IAAI,SAAS,GAAG,EAAE,OAAO,EAAE,CAAC;GAWvF,MAAM,OACH,WAAW,KAAK,MAAM,QAAQ,0CAAwC,CAAC,CAAC,MAAM,GAAG,EAAE,SAAS,IAAK,CAAC,CAAA,CAClG,gBAAgB,CAAC;GACpB,IAAI,cACF,MAAM,KAAK,MAAM,iBAAiB,OAAO,CAAC,MAAM,CAAC,GAAG,aAAa,cAAc,EAAE,SAAS,IAAK,CAAC;GASlG,MAAM,oBAAoB,MAAM,KAAK,qBAAqB,cAAc,IAAI;GAC5E,IAAI,mBAAmB;IACrB,MAAM,QAAQ,MAAM,kBAAkB,YAAY;IAClD,IAAI,OAAO;KACT,MAAM,OAAO,MAAM,IAAI,MAAM,QAAQ;KACrC,MAAM,OAAO,MAAM,IAAI,KAAK,IAAI,MAAM,SAAS,GAAG,CAAC;KACnD,MAAM,KAAK,MAAM,MAAM,KAAK,MAAM,MAAM,EAAE,OAAO,EAAE,CAAC;KAIpD,MAAM,iBACJ,kBAAkB,UAAU,OAAO,GAAG,aAAa,+BAA+B,MAAM,QAAQ;KAClG,IAAI,CAAE,MAAM,SAAS,GAAI;MACvB,MAAM,QAAQ,KAAK,IAAI;MACvB,IAAI,QAAQ;MACZ,OAAO,KAAK,IAAI,IAAI,QAAQ,KAAM;OAChC,MAAM,KAAK,MAAM,eAAe,GAAG;OACnC,SAAS,QAAQ,KAAK;OACtB,MAAM,KAAK,UAAU,KAAK,UAAU,IAAI,IAAI;OAC5C,MAAM,KAAK,UAAU,KAAK,UAAU,IAAI,IAAI;OAC5C,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO,IAAI,OAAO,IAAI,EAAE,OAAO,EAAE,CAAC;OAC9D,IAAI,MAAM,SAAS,GACjB;MAEJ;MACA,MAAM,OACH,WAAW,kBAAkB,UAAU,OAAO,GAAG,aAAa,+BAA+B,CAAC,GAAG,EAChG,SAAS,IACX,CAAC,CAAA,CACA,KAAK,QAAQ;KAClB;KAIA,MAAM,WAAW,MAAM,kBAAkB,YAAY;KACrD,IAAI,UACF,MAAM,KAAK,MAAM,MAAM,KAAK,SAAS,IAAI,SAAS,QAAQ,GAAG,SAAS,IAAI,SAAS,SAAS,GAAG,EAC7F,OAAO,EACT,CAAC;IAEL;GACF;EACF,OAAO;GAGL,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,QAAQ,GAAG,OAAO,IAAI,IAAI,IAAI,IAAI,SAAS,GAAG,EAAE,OAAO,EAAE,CAAC;GAC7G,MAAM,KAAK,MAAM,eAAe,GAAG;EACrC;EACA,MAAM,KAAK,MAAM,MAAM,GAAG;CAC5B;;;;;;CAOA,MAAc,qBACZ,cACA,MACuE;EACvE,MAAM,SAAS,SAAS,SAAS,SAAS;EAQ1C,MAAM,UAAS,MAPM,aAAa,gBAAgB,IAAI,cAAc;GAClE,IAAI,UAA0B,YAAY,GAAG,yBAAyB,GAAG;GACzE,OAAO,WAAW,CAAC,QAAQ,aAAa,kCAAkC,GACxE,UAAU,YAAY,QAAQ,yBAAyB,QAAQ;GAEjE,OAAO;EACT,GAAG,MAAM,EAAA,CACa,UAAU;EAChC,IAAI,CAAC,QACH,OAAO;EAKT,OAAO,MADc,OAAO,UAAU,OAAO,OAAO,IAAI,IACxC,SAAS;CAC3B;;;;;;;;;;;;;;CAeA,MAAM,wBAAwB,YAAqB,YAAqB,aAAa;EAAE,GAAG;EAAG,GAAG;CAAE,GAAkB;EAClH,MAAM,SAAS,KAAK,QAAQ,YAAY,4BAA4B;EACpE,MAAM,UAAU,MAAM,WAAW,YAAY;EAC7C,IAAI,CAAC,SACH;EAIF,MAAM,QAAQ,QAAQ,IAAI,QAAQ,QAAQ;EAC1C,MAAM,QAAQ,QAAQ,IAAI;EAK1B,MAAM,aAAa,MAAM,WAAW,YAAY;EAChD,MAAM,cAAc,CAAC,cAAc,WAAW,KAAK,QAAQ;EAE3D,MAAM,OAAO,MAAM;EACnB,MAAM,KAAK,MAAM,MAAM,KAAK;EAE5B,MAAM,KAAK,MAAM,eAAe,GAAG;EAEnC,IAAI,CAAC,aAAa;GAEhB,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO,OAAO,EAAE,OAAO,EAAE,CAAC;GACtD,MAAM,UAAU,MAAM,WAAW,YAAY;GAC7C,IAAI,SAAS;IACX,MAAM,QAAQ,WAAW,IAAI,QAAQ,IAAI,QAAQ,QAAQ;IACzD,MAAM,QAAQ,WAAW,IAAI,QAAQ,IAAI,QAAQ,SAAS;IAC1D,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO,OAAO,EAAE,OAAO,EAAE,CAAC;IACtD,MAAM,KAAK,MAAM,eAAe,GAAG;IACnC,MAAM,KAAK,MAAM,MAAM,GAAG;IAC1B;GACF;GACA,MAAM,KAAK,MAAM,MAAM,GAAG;GAC1B;EACF;EAGA,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO,OAAO,EAAE,OAAO,EAAE,CAAC;EAGtD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;GAE3B,MAAM,KAAK,MAAM,eAAe,GAAG;GAEnC,MAAM,KAAK,MAAM,MAAM,KAAK,QAAS,IAAI,GAAI,OAAO,EAAE,OAAO,EAAE,CAAC;GAEhE,MAAM,UAAU,MAAM,WAAW,YAAY;GAC7C,IAAI,WAAW,QAAQ,IAAI,QAAQ,SAAS,OAAO;IAEjD,MAAM,WAAW,MAAM,WAAW,YAAY;IAC9C,IAAI,CAAC,UAAU;KACb,MAAM,KAAK,MAAM,MAAM,GAAG;KAC1B;IACF;IAEA,MAAM,QAAQ,WAAW,IAAI,SAAS,IAAI,SAAS,QAAQ;IAC3D,MAAM,QAAQ,WAAW,IAAI,SAAS,IAAI,SAAS,SAAS;IAC5D,MAAM,KAAK,MAAM,MAAM,KAAK,OAAO,OAAO,EAAE,OAAO,EAAE,CAAC;IAEtD,MAAM,WAAW,QAAQ,EAAE,OAAO,UAAU,CAAC;IAC7C,MAAM,KAAK,MAAM,eAAe,GAAG;IACnC,MAAM,KAAK,MAAM,MAAM,GAAG;IAC1B;GACF;EACF;EAGA,MAAM,KAAK,MAAM,MAAM,GAAG;CAC5B;AACF"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { a as Focus, t as Mosaic } from "./chunk-Mosaic.mjs";
|
|
2
|
+
import { useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Card, Icon, IconButton, Popover } from "@dxos/react-ui";
|
|
4
|
+
import { Dnd, ResizeHandle, resizeAttributes, sizeStyle } from "@dxos/react-ui-dnd";
|
|
5
|
+
import { JsonHighlighter } from "@dxos/react-ui-syntax-highlighter";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { DXN, Obj, Ref, Type } from "@dxos/echo";
|
|
8
|
+
import { Menu, createMenuAction } from "@dxos/react-ui-menu";
|
|
9
|
+
import * as Schema from "effect/Schema";
|
|
10
|
+
import { EntityId } from "@dxos/keys";
|
|
11
|
+
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
12
|
+
//#region src/testing/decorator.tsx
|
|
13
|
+
var withMosaic = () => {
|
|
14
|
+
return (Story) => /* @__PURE__ */ jsx(Dnd.Root, { children: /* @__PURE__ */ jsx(Story, {}) });
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/testing/types.ts
|
|
18
|
+
var TestItem = class extends Type.makeObject(DXN.make("com.example.type.item", "0.1.0"))(Schema.Struct({
|
|
19
|
+
name: Schema.String,
|
|
20
|
+
description: Schema.optional(Schema.String),
|
|
21
|
+
label: Schema.optional(Schema.String)
|
|
22
|
+
})) {};
|
|
23
|
+
var TestColumn = class extends Type.makeObject(DXN.make("com.example.type.column", "0.1.0"))(Schema.Struct({
|
|
24
|
+
id: EntityId,
|
|
25
|
+
name: Schema.String,
|
|
26
|
+
items: Schema.mutable(Schema.Array(Ref.Ref(TestItem)))
|
|
27
|
+
})) {};
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/testing/CardContainer.tsx
|
|
30
|
+
var DEFAULT_BLOCK_SIZE = 22;
|
|
31
|
+
var MIN_BLOCK_SIZE = 8;
|
|
32
|
+
var CardContainer = ({ children, role, icon = "ph--arrow-line-down--regular" }) => {
|
|
33
|
+
switch (role) {
|
|
34
|
+
case "popover": return /* @__PURE__ */ jsx("div", {
|
|
35
|
+
className: "flex justify-center",
|
|
36
|
+
children: /* @__PURE__ */ jsx(PopoverCardContainer, {
|
|
37
|
+
icon,
|
|
38
|
+
children
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
default: return /* @__PURE__ */ jsx(IntrinsicCardContainer, { children });
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var PopoverCardContainer = ({ children, icon = "ph--arrow-line-down--regular" }) => {
|
|
45
|
+
return /* @__PURE__ */ jsxs(Popover.Root, {
|
|
46
|
+
open: true,
|
|
47
|
+
children: [/* @__PURE__ */ jsx(Popover.Trigger, {
|
|
48
|
+
asChild: true,
|
|
49
|
+
children: /* @__PURE__ */ jsx(Icon, { icon })
|
|
50
|
+
}), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsxs(Popover.Content, {
|
|
51
|
+
onOpenAutoFocus: (event) => event.preventDefault(),
|
|
52
|
+
children: [/* @__PURE__ */ jsx(Popover.Viewport, {
|
|
53
|
+
classNames: "dx-card-popover",
|
|
54
|
+
children
|
|
55
|
+
}), /* @__PURE__ */ jsx(Popover.Arrow, {})]
|
|
56
|
+
}) })]
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
var IntrinsicCardContainer = ({ children, defaultSize, size: propSize, onSizeChange }) => {
|
|
60
|
+
const [size = DEFAULT_BLOCK_SIZE, setSize] = useControllableState({
|
|
61
|
+
prop: propSize,
|
|
62
|
+
defaultProp: defaultSize,
|
|
63
|
+
onChange: onSizeChange
|
|
64
|
+
});
|
|
65
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
66
|
+
className: "relative p-2 grid overflow-hidden border-2 border-dashed border-green-500 rounded-lg",
|
|
67
|
+
style: sizeStyle(size, "horizontal"),
|
|
68
|
+
...resizeAttributes,
|
|
69
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
70
|
+
className: "dx-container flex flex-col",
|
|
71
|
+
children
|
|
72
|
+
}), /* @__PURE__ */ jsx(ResizeHandle, {
|
|
73
|
+
side: "inline-end",
|
|
74
|
+
fallbackSize: DEFAULT_BLOCK_SIZE,
|
|
75
|
+
minSize: MIN_BLOCK_SIZE,
|
|
76
|
+
size,
|
|
77
|
+
onSizeChange: setSize
|
|
78
|
+
})]
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/testing/DefaultStackTile.tsx
|
|
83
|
+
var DefaultStackTile = (props) => {
|
|
84
|
+
const dragHandleRef = useRef(null);
|
|
85
|
+
const [open, setOpen] = useState(false);
|
|
86
|
+
const menuItems = useMemo(() => [createMenuAction("toggle-details", () => setOpen((prev) => !prev), {
|
|
87
|
+
label: open ? "Hide details" : "Show details",
|
|
88
|
+
icon: "ph--circle-dashed--regular"
|
|
89
|
+
})], [open]);
|
|
90
|
+
return /* @__PURE__ */ jsx(Menu.Root, { children: /* @__PURE__ */ jsx(Mosaic.Tile, {
|
|
91
|
+
...props,
|
|
92
|
+
asChild: true,
|
|
93
|
+
children: /* @__PURE__ */ jsx(Focus.Item, {
|
|
94
|
+
asChild: true,
|
|
95
|
+
children: /* @__PURE__ */ jsxs(Card.Root, {
|
|
96
|
+
fullWidth: true,
|
|
97
|
+
classNames: "dx-current dx-hover",
|
|
98
|
+
children: [/* @__PURE__ */ jsxs(Card.Header, { children: [
|
|
99
|
+
/* @__PURE__ */ jsx(Card.DragHandle, { ref: dragHandleRef }),
|
|
100
|
+
/* @__PURE__ */ jsx(Card.Title, { children: Obj.getLabel(props.data) ?? props.data.id }),
|
|
101
|
+
/* @__PURE__ */ jsx(Card.Block, {
|
|
102
|
+
end: true,
|
|
103
|
+
children: /* @__PURE__ */ jsx(Menu.Trigger, {
|
|
104
|
+
asChild: true,
|
|
105
|
+
disabled: !menuItems?.length,
|
|
106
|
+
children: /* @__PURE__ */ jsx(IconButton, {
|
|
107
|
+
iconOnly: true,
|
|
108
|
+
variant: "ghost",
|
|
109
|
+
icon: "ph--dots-three-vertical--regular",
|
|
110
|
+
label: "Menu"
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
}),
|
|
114
|
+
/* @__PURE__ */ jsx(Menu.Content, { items: menuItems })
|
|
115
|
+
] }), open && /* @__PURE__ */ jsx(Card.Row, { children: /* @__PURE__ */ jsx(JsonHighlighter, {
|
|
116
|
+
data: props.data,
|
|
117
|
+
classNames: "text-xs"
|
|
118
|
+
}) })]
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
}) });
|
|
122
|
+
};
|
|
123
|
+
DefaultStackTile.displayName = "DefaultStackTile";
|
|
124
|
+
//#endregion
|
|
125
|
+
export { CardContainer, DefaultStackTile, IntrinsicCardContainer, PopoverCardContainer, TestColumn, TestItem, withMosaic };
|
|
126
|
+
|
|
127
|
+
//# sourceMappingURL=testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.mjs","names":[],"sources":["../../src/testing/decorator.tsx","../../src/testing/types.ts","../../src/testing/CardContainer.tsx","../../src/testing/DefaultStackTile.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Decorator } from '@storybook/react-vite';\nimport React from 'react';\n\nimport { Dnd } from '@dxos/react-ui-dnd';\n\nexport const withMosaic = (): Decorator => {\n return (Story) => (\n <Dnd.Root>\n <Story />\n </Dnd.Root>\n );\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { DXN, Ref, Type } from '@dxos/echo';\nimport { EntityId } from '@dxos/keys';\n\n//\n// Test Data\n//\n\nexport class TestItem extends Type.makeObject<TestItem>(DXN.make('com.example.type.item', '0.1.0'))(\n Schema.Struct({\n name: Schema.String,\n description: Schema.optional(Schema.String),\n label: Schema.optional(Schema.String),\n }),\n) {}\n\nexport class TestColumn extends Type.makeObject<TestColumn>(DXN.make('com.example.type.column', '0.1.0'))(\n Schema.Struct({\n id: EntityId,\n name: Schema.String,\n items: Schema.mutable(Schema.Array(Ref.Ref(TestItem))),\n }),\n) {}\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type PropsWithChildren } from 'react';\n\nimport { Icon, Popover } from '@dxos/react-ui';\nimport { ResizeHandle, type Size, resizeAttributes, sizeStyle } from '@dxos/react-ui-dnd';\n\nconst DEFAULT_BLOCK_SIZE = 22;\nconst MIN_BLOCK_SIZE = 8;\n\n//\n// Card container.\n//\n\nexport type CardContainerProps = PropsWithChildren<{ role?: 'popover' | 'intrinsic'; icon?: string }>;\n\nexport const CardContainer = ({ children, role, icon = 'ph--arrow-line-down--regular' }: CardContainerProps) => {\n switch (role) {\n case 'popover':\n return (\n <div className='flex justify-center'>\n <PopoverCardContainer icon={icon}>{children}</PopoverCardContainer>\n </div>\n );\n case 'intrinsic':\n default:\n return <IntrinsicCardContainer>{children}</IntrinsicCardContainer>;\n }\n};\n\n//\n// Popover\n//\n\nexport type PopoverCardContainerProps = PropsWithChildren<{ icon?: string }>;\n\nexport const PopoverCardContainer = ({\n children,\n icon = 'ph--arrow-line-down--regular',\n}: PopoverCardContainerProps) => {\n return (\n <Popover.Root open>\n <Popover.Trigger asChild>\n <Icon icon={icon} />\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Content onOpenAutoFocus={(event: Event) => event.preventDefault()}>\n <Popover.Viewport classNames='dx-card-popover'>{children}</Popover.Viewport>\n <Popover.Arrow />\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n};\n\n//\n// Intrinsic card container (size constrained by card itself).\n//\n\nexport type IntrinsicCardContainerProps = PropsWithChildren<{\n defaultSize?: Size;\n size?: Size;\n onSizeChange?: (size: Size, commit?: boolean) => void;\n}>;\n\nexport const IntrinsicCardContainer = ({\n children,\n defaultSize,\n size: propSize,\n onSizeChange,\n}: IntrinsicCardContainerProps) => {\n const [size = DEFAULT_BLOCK_SIZE, setSize] = useControllableState<Size>({\n prop: propSize,\n defaultProp: defaultSize,\n onChange: onSizeChange,\n });\n\n return (\n <div\n className='relative p-2 grid overflow-hidden border-2 border-dashed border-green-500 rounded-lg'\n style={sizeStyle(size, 'horizontal')}\n {...resizeAttributes}\n >\n <div className='dx-container flex flex-col'>{children}</div>\n <ResizeHandle\n side='inline-end'\n fallbackSize={DEFAULT_BLOCK_SIZE}\n minSize={MIN_BLOCK_SIZE}\n size={size}\n onSizeChange={setSize}\n />\n </div>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo, useRef, useState } from 'react';\n\nimport { Obj } from '@dxos/echo';\nimport { Card, IconButton } from '@dxos/react-ui';\nimport { Menu, createMenuAction } from '@dxos/react-ui-menu';\nimport { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';\n\nimport { Focus, Mosaic, type MosaicStackTileComponent } from '../components';\n\nexport const DefaultStackTile: MosaicStackTileComponent<Obj.Any> = (props) => {\n const dragHandleRef = useRef<HTMLButtonElement>(null);\n const [open, setOpen] = useState(false);\n const menuItems = useMemo(\n () => [\n createMenuAction('toggle-details', () => setOpen((prev) => !prev), {\n label: open ? 'Hide details' : 'Show details',\n icon: 'ph--circle-dashed--regular',\n }),\n ],\n [open],\n );\n\n return (\n <Menu.Root>\n {/*\n * `Mosaic.Tile` sets `aria-current` from `props.current`, which the\n * Slot composition propagates down to `Card.Root`'s div. That's what\n * makes `dx-current` (an `aria-[current=true]:` utility) actually\n * fire here. See `ui-theme/src/css/components/selected.md`.\n */}\n <Mosaic.Tile {...props} asChild>\n <Focus.Item asChild>\n <Card.Root fullWidth classNames='dx-current dx-hover'>\n <Card.Header>\n <Card.DragHandle ref={dragHandleRef} />\n <Card.Title>{Obj.getLabel(props.data) ?? props.data.id}</Card.Title>\n <Card.Block end>\n <Menu.Trigger asChild disabled={!menuItems?.length}>\n <IconButton iconOnly variant='ghost' icon='ph--dots-three-vertical--regular' label='Menu' />\n </Menu.Trigger>\n </Card.Block>\n <Menu.Content items={menuItems} />\n </Card.Header>\n {open && (\n <Card.Row>\n <JsonHighlighter data={props.data} classNames='text-xs' />\n </Card.Row>\n )}\n </Card.Root>\n </Focus.Item>\n </Mosaic.Tile>\n </Menu.Root>\n );\n};\n\nDefaultStackTile.displayName = 'DefaultStackTile';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/translations.ts
|
|
2
|
+
var translationKey = "@dxos/react-ui-mosaic";
|
|
3
|
+
var translations = [{ "en-US": { [translationKey]: {
|
|
4
|
+
"action-menu.label": "Actions",
|
|
5
|
+
"add-item.label": "Add item",
|
|
6
|
+
"delete-menu.label": "Delete"
|
|
7
|
+
} } }];
|
|
8
|
+
//#endregion
|
|
9
|
+
export { translationKey, translations };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=translations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nexport const translationKey = '@dxos/react-ui-mosaic';\n\nexport const translations = [\n {\n 'en-US': {\n [translationKey]: {\n 'action-menu.label': 'Actions',\n 'add-item.label': 'Add item',\n 'delete-menu.label': 'Delete',\n },\n },\n },\n] as const satisfies Resource[];\n"],"mappings":";AAMA,IAAa,iBAAiB;AAE9B,IAAa,eAAe,CAC1B,EACE,SAAS,GACN,iBAAiB;CAChB,qBAAqB;CACrB,kBAAkB;CAClB,qBAAqB;AACvB,EACF,EACF,CACF"}
|
|
@@ -1,37 +1,18 @@
|
|
|
1
|
-
import { type Atom } from '@effect-atom/atom-react';
|
|
2
1
|
import React, { type PropsWithChildren, type ReactElement, type Ref as ReactRef } from 'react';
|
|
3
2
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
4
|
-
import { type
|
|
5
|
-
import { type
|
|
3
|
+
import { type DndContainerHandler } from '@dxos/react-ui-dnd';
|
|
4
|
+
import { type MosaicPlaceholderProps, type MosaicStackProps } from '../Mosaic';
|
|
5
|
+
import { type BoardContextValue } from './BoardContext';
|
|
6
|
+
import { type BoardColumnProps } from './Column';
|
|
6
7
|
import { type BoardItemProps } from './Item';
|
|
7
|
-
export interface BoardModel<TColumn = any, TItem = any> {
|
|
8
|
-
getColumnId: GetId<TColumn>;
|
|
9
|
-
getItemId: GetId<TItem>;
|
|
10
|
-
isColumn: (obj: unknown) => obj is TColumn;
|
|
11
|
-
isItem: (obj: unknown) => obj is TItem;
|
|
12
|
-
columns: Atom.Atom<readonly TColumn[] | TColumn[]>;
|
|
13
|
-
items: (column: TColumn) => Atom.Atom<TItem[]>;
|
|
14
|
-
getColumns: () => TColumn[];
|
|
15
|
-
getItems: (column: TColumn) => TItem[];
|
|
16
|
-
onColumnCreate?: () => Promise<TColumn>;
|
|
17
|
-
onColumnDelete?: (column: TColumn) => void;
|
|
18
|
-
onItemCreate?: (column: TColumn) => Promise<TItem>;
|
|
19
|
-
onItemDelete?: (column: TColumn, item: TItem) => void;
|
|
20
|
-
}
|
|
21
|
-
type BoardContextValue<TColumn = any, TItem = any> = {
|
|
22
|
-
model: BoardModel<TColumn, TItem>;
|
|
23
|
-
};
|
|
24
|
-
/** Hook to read the board model from context (e.g. in custom column tiles). Pass TColumn and TItem for typed model. */
|
|
25
|
-
declare function useBoard<TColumn = any, TItem = any>(displayName?: string): BoardContextValue<TColumn, TItem>;
|
|
26
8
|
type BoardRootProps<TColumn = any, TItem = any> = PropsWithChildren<BoardContextValue<TColumn, TItem>>;
|
|
27
9
|
declare function BoardRootInner({ model, children }: BoardRootProps): React.JSX.Element;
|
|
28
10
|
declare namespace BoardRootInner {
|
|
29
11
|
var displayName: string;
|
|
30
12
|
}
|
|
31
13
|
type BoardContentProps<TColumn = any> = ThemedClassName<{
|
|
32
|
-
id: string;
|
|
33
14
|
debug?: boolean;
|
|
34
|
-
eventHandler?:
|
|
15
|
+
eventHandler?: DndContainerHandler<TColumn>;
|
|
35
16
|
Tile?: MosaicStackProps<TColumn>['Tile'];
|
|
36
17
|
}>;
|
|
37
18
|
declare function BoardPlaceholder(props: MosaicPlaceholderProps<number>): React.JSX.Element;
|
|
@@ -59,12 +40,12 @@ export declare const Board: {
|
|
|
59
40
|
dragHandleRef: ReactRef<HTMLButtonElement>;
|
|
60
41
|
}, "className"> & {
|
|
61
42
|
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
62
|
-
} & Pick<React.HTMLAttributes<Element>, "children" | "
|
|
43
|
+
} & Pick<React.HTMLAttributes<Element>, "children" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
63
44
|
Body: React.ForwardRefExoticComponent<Omit<Pick<BoardColumnProps<any>, "data"> & Pick<import("..").MosaicContainerProps, "debug" | "eventHandler"> & {
|
|
64
45
|
Tile?: MosaicStackProps<import("@dxos/echo/Obj").Unknown>['Tile'];
|
|
65
46
|
}, "className"> & {
|
|
66
47
|
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
67
|
-
} & Pick<React.HTMLAttributes<Element>, "children" | "
|
|
48
|
+
} & Pick<React.HTMLAttributes<Element>, "children" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
68
49
|
Footer: React.ForwardRefExoticComponent<Omit<{}, "className"> & {
|
|
69
50
|
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
70
51
|
} & {
|
|
@@ -83,6 +64,5 @@ export declare const Board: {
|
|
|
83
64
|
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
84
65
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
85
66
|
};
|
|
86
|
-
export { useBoard, useBoardColumn };
|
|
87
67
|
export type { BoardColumnProps, BoardContentProps, BoardItemProps, BoardRootProps };
|
|
88
68
|
//# sourceMappingURL=Board.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Board.d.ts","sourceRoot":"","sources":["../../../../../src/components/Board/Board.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Board.d.ts","sourceRoot":"","sources":["../../../../../src/components/Board/Board.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EACZ,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,GAAG,IAAI,QAAQ,EAIrB,MAAM,OAAO,CAAC;AAEf,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EAAE,KAAK,mBAAmB,EAAqB,MAAM,oBAAoB,CAAC;AAMjF,OAAO,EAAU,KAAK,sBAAsB,EAAE,KAAK,gBAAgB,EAAgB,MAAM,WAAW,CAAC;AACrG,OAAO,EAAwB,KAAK,iBAAiB,EAAmB,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAe,KAAK,gBAAgB,EAAsB,MAAM,UAAU,CAAC;AAClF,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,QAAQ,CAAC;AAQxD,KAAK,cAAc,CAAC,OAAO,GAAG,GAAG,EAAE,KAAK,GAAG,GAAG,IAAI,iBAAiB,CAAC,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;gCAE/E,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,cAAc;;;;AAc3D,KAAK,iBAAiB,CAAC,OAAO,GAAG,GAAG,IAAI,eAAe,CAAC;IACtD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;CAC1C,CAAC,CAAC;kCA+CuB,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC;;;;AAkB/D,eAAO,MAAM,UAAU;;wCAUrB,CAAC;AAQH,eAAO,MAAM,KAAK;IAChB,IAAI,GAhG+B,OAAO,QAAQ,KAAK,eAAe,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,YAAY;IAiGrH,OAAO,GAhDkC,OAAO,eACzC,iBAAiB,CAAC,OAAO,CAAC,GAAG;QAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAA;KAAE,KACnE,YAAY;IA+Cf,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;IACN,IAAI;;;IACJ,WAAW;gBAzCoB,sBAAsB,CAAC,MAAM,CAAC;;;IA0C7D,KAAK;;;CACN,CAAC;AAEF,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Board.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Board/Board.stories.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAA8B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Board.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Board/Board.stories.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAA8B,MAAM,OAAO,CAAC;AA8CnD,KAAK,SAAS,GAAG;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAsIF,QAAA,MAAM,IAAI;;8CAvByD,SAAS;;;;;;;;;;;;;;;;;;;;;;CAoDvC,CAAC;eAEvB,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAKrB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAK1B,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAAU,CAAC;AAE/B,eAAO,MAAM,WAAW,EAAE,KAIzB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAKnB,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAkBlB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const BOARD_COLUMN_CONTEXT_NAME = "Board.Column";
|
|
2
|
+
export type BoardColumnContextValue<TColumn = unknown> = {
|
|
3
|
+
column: TColumn;
|
|
4
|
+
};
|
|
5
|
+
export declare const BoardColumnProvider: import("react").FC<BoardColumnContextValue<unknown> & {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}>, useBoardColumnContext: (consumerName: string) => BoardColumnContextValue<unknown> | null;
|
|
8
|
+
/** Returns the current column when rendered inside a board column (e.g., in column header or item tile). */
|
|
9
|
+
export declare function useBoardColumn<TColumn = unknown>(): TColumn | undefined;
|
|
10
|
+
//# sourceMappingURL=BoardColumnContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BoardColumnContext.d.ts","sourceRoot":"","sources":["../../../../../src/components/Board/BoardColumnContext.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,yBAAyB,iBAAiB,CAAC;AAExD,MAAM,MAAM,uBAAuB,CAAC,OAAO,GAAG,OAAO,IAAI;IACvD,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAO,mBAAmB;;IAAE,qBAAqB,mEAGvD,CAAC;AAEF,4GAA4G;AAC5G,wBAAgB,cAAc,CAAC,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,SAAS,CAGvE"}
|