@shiguri/solid-grid 0.0.1 → 0.1.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/LICENSE +21 -0
- package/README.md +35 -18
- package/dist/gridsheet-D9A0kuhj.d.ts +138 -0
- package/dist/index.d.ts +73 -69
- package/dist/index.js +673 -301
- package/dist/index.js.map +1 -1
- package/dist/preset-tailwind.css +1 -0
- package/dist/presets.d.ts +9 -0
- package/dist/presets.js +56 -0
- package/dist/presets.js.map +1 -0
- package/package.json +26 -9
- package/dist/index.d.ts.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.tsx"],"sourcesContent":["import {\n batch,\n createEffect,\n createMemo,\n createSignal,\n For,\n Index,\n onCleanup,\n onMount,\n} from \"solid-js\";\nimport type { JSX } from \"solid-js/jsx-runtime\";\n\nexport interface CellPosition {\n row: number;\n col: number;\n}\n\nexport interface CellRange {\n min: CellPosition;\n max: CellPosition;\n}\n\nfunction isPositionInRange(pos: CellPosition, range: CellRange): boolean {\n return (\n pos.row >= range.min.row &&\n pos.row <= range.max.row &&\n pos.col >= range.min.col &&\n pos.col <= range.max.col\n );\n}\n\nfunction normalizeRange(pos1: CellPosition, pos2: CellPosition): CellRange {\n return {\n min: {\n row: Math.min(pos1.row, pos2.row),\n col: Math.min(pos1.col, pos2.col),\n },\n max: {\n row: Math.max(pos1.row, pos2.row),\n col: Math.max(pos1.col, pos2.col),\n },\n };\n}\n\nexport interface CellRenderContext<T> {\n /** Row index */\n row: number;\n\n /** Column index */\n col: number;\n\n /** Cell value */\n value: T;\n\n /** Is this the active cell (focused) */\n isActive: boolean;\n\n /** Is this cell currently selected */\n isSelected: boolean;\n\n /** Is this cell currently being edited */\n isEditing: boolean;\n\n /** Solid ref for scrolling, focusing, measuring, etc. */\n cellRef: HTMLTableCellElement | undefined;\n\n /** Enter editing mode for this cell */\n beginEdit: () => void;\n\n /** Commit edit with new value */\n commitEdit: (value: T) => void;\n\n /** Exit editing mode for this cell */\n cancelEditing: () => void;\n}\n\nexport interface GridsheetProps<T> {\n /** 2D matrix of values */\n data: T[][];\n onDataChange?: (next: T[][]) => void;\n\n /** Renderer for each cell */\n renderCell: (ctx: CellRenderContext<T>) => JSX.Element;\n\n /** Currently focused cell */\n activeCell?: CellPosition | null;\n onActiveCellChange?: (pos: CellPosition | null) => void;\n\n /** Current selection range */\n selection?: CellRange | null;\n onSelectionChange?: (range: CellRange | null) => void;\n\n /** Is the active cell in editing mode */\n isEditing?: boolean;\n onIsEditingChange?: (isEditing: boolean) => void;\n\n ref?: HTMLTableElement | ((el: HTMLTableElement) => void) | undefined;\n class?: string;\n style?: JSX.CSSProperties | string;\n classes?: {\n cell?: string | ((ctx: CellRenderContext<T>) => string);\n row?: string | ((ctx: { rowIndex: number }) => string);\n rowHeader?:\n | string\n | ((ctx: { rowIndex: number; isSelected: boolean }) => string);\n colHeader?:\n | string\n | ((ctx: { colIndex: number; isSelected: boolean }) => string);\n corner?: string;\n header?: string;\n body?: string;\n };\n}\n\ntype SelectionMode = \"cell\" | \"row\" | \"col\";\nconst DEFAULT_SELECTION_MODE: SelectionMode = \"cell\";\n\nexport function Gridsheet<T>(props: GridsheetProps<T>): JSX.Element {\n const numRows = createMemo(() => props.data.length);\n const numCols = createMemo(() => (props.data[0] ? props.data[0].length : 0));\n\n const [innerActiveCell, setInnerActiveCell] =\n createSignal<CellPosition | null>(null);\n const activeCell = createMemo(() =>\n props.activeCell === undefined ? innerActiveCell() : props.activeCell,\n );\n const setActiveCell = (pos: CellPosition | null) => {\n // propsでactiveCellを管理している場合でも、内部stateを更新する\n // props.activeCellがundefinedに変更される可能性があるため\n setInnerActiveCell(pos);\n\n if (props.onActiveCellChange) {\n props.onActiveCellChange(pos);\n }\n };\n\n const isCellActive = (pos: CellPosition) => {\n const ac = activeCell();\n return ac !== null && ac.row === pos.row && ac.col === pos.col;\n };\n\n const [innerSelection, setInnerSelection] = createSignal<CellRange | null>(\n null,\n );\n const selection = createMemo(() =>\n props.selection === undefined ? innerSelection() : props.selection,\n );\n const setSelection = (range: CellRange | null) => {\n const normalizedRange = range ? normalizeRange(range.min, range.max) : null;\n // propsでselectionを管理している場合でも、内部stateを更新する\n // props.selectionがundefinedに変更される可能性があるため\n setInnerSelection(normalizedRange);\n\n if (props.onSelectionChange) {\n props.onSelectionChange(normalizedRange);\n }\n };\n\n const isCellSelected = (pos: CellPosition) => {\n const sel = selection();\n return sel !== null && isPositionInRange(pos, sel);\n };\n\n const isRowHeaderSelected = (rowIndex: number) => {\n const sel = selection();\n return sel !== null && rowIndex >= sel.min.row && rowIndex <= sel.max.row;\n };\n\n const isColHeaderSelected = (colIndex: number) => {\n const sel = selection();\n return sel !== null && colIndex >= sel.min.col && colIndex <= sel.max.col;\n };\n\n const [innerIsEditing, setInnerIsEditing] = createSignal<boolean>(false);\n const isEditing = createMemo(() =>\n props.isEditing === undefined ? innerIsEditing() : props.isEditing,\n );\n const setIsEditing = (editing: boolean) => {\n setInnerIsEditing(editing);\n\n if (props.onIsEditingChange) {\n props.onIsEditingChange(editing);\n }\n };\n\n const isCellEditing = (pos: CellPosition) => {\n return isEditing() && isCellActive(pos);\n };\n\n const beginCellEdit = (pos: CellPosition) => {\n batch(() => {\n setIsEditing(true);\n setActiveCell(pos);\n setSelection(normalizeRange(pos, pos));\n });\n };\n\n const commitCellEdit = (pos: CellPosition, value: T) => {\n const nextData = props.data.map((row) => row.slice());\n\n const targetRow = nextData[pos.row];\n if (targetRow && pos.col >= 0 && pos.col < targetRow.length) {\n targetRow[pos.col] = value;\n if (props.onDataChange) {\n props.onDataChange(nextData);\n }\n }\n\n setIsEditing(false);\n };\n\n const cancelCellEdit = () => {\n setIsEditing(false);\n };\n\n const [isMouseDown, setIsMouseDown] = createSignal(false);\n const [selectionMode, setSelectionMode] = createSignal<SelectionMode>(\n DEFAULT_SELECTION_MODE,\n );\n const [selectionAnchor, setSelectionAnchor] =\n createSignal<CellPosition | null>(null);\n\n let previousBodyUserSelect: string | null = null;\n const disableTextSelectionDuringDrag = () => {\n if (typeof document === \"undefined\" || previousBodyUserSelect !== null)\n return;\n const body = document.body;\n if (!body) return;\n previousBodyUserSelect = body.style.userSelect;\n body.style.userSelect = \"none\";\n };\n const restoreTextSelectionAfterDrag = () => {\n if (typeof document === \"undefined\" || previousBodyUserSelect === null)\n return;\n const body = document.body;\n if (body) {\n body.style.userSelect = previousBodyUserSelect;\n }\n previousBodyUserSelect = null;\n };\n\n const handleMouseUp = () => {\n setIsMouseDown(false);\n setSelectionMode(DEFAULT_SELECTION_MODE);\n setSelectionAnchor(null);\n restoreTextSelectionAfterDrag();\n };\n onMount(() => {\n window.addEventListener(\"mouseup\", handleMouseUp);\n });\n onCleanup(() => {\n window.removeEventListener(\"mouseup\", handleMouseUp);\n restoreTextSelectionAfterDrag();\n });\n\n const handleMouseDownOnCell = (pos: CellPosition, e: MouseEvent) => {\n if (e.button !== 0) return;\n\n // 編集中のセルは選択操作を無効化し、編集状態を維持する\n if (isCellEditing(pos)) return;\n\n // ダブルクリック(2回目のmousedown)で即座に編集に入る\n if (e.detail === 2) {\n e.preventDefault();\n beginCellEdit(pos);\n return;\n }\n\n e.preventDefault();\n\n batch(() => {\n disableTextSelectionDuringDrag();\n setIsMouseDown(true);\n setSelectionMode(\"cell\");\n setSelectionAnchor(pos);\n\n setIsEditing(false);\n setSelection(normalizeRange(pos, pos));\n setActiveCell(pos);\n });\n };\n const handleMouseOverOnCell = (pos: CellPosition, e: MouseEvent) => {\n // ドラッグされていない場合は何もしない\n if ((e.buttons & 1) === 0) return;\n\n batch(() => {\n if (!isMouseDown() || selectionMode() !== \"cell\") return;\n\n const start = selectionAnchor();\n if (start) {\n setSelection(normalizeRange(start, pos));\n } else {\n console.warn(\"selectionAnchor is null during mouse drag selection\");\n }\n });\n };\n\n const handleMouseDownOnRowHeader = (rowIndex: number) => {\n if (numCols() === 0) {\n return;\n }\n\n batch(() => {\n disableTextSelectionDuringDrag();\n setIsMouseDown(true);\n setSelectionMode(\"row\");\n const start: CellPosition = { row: rowIndex, col: 0 };\n const end: CellPosition = { row: rowIndex, col: numCols() - 1 };\n setSelectionAnchor(start);\n\n setIsEditing(false);\n setSelection(normalizeRange(start, end));\n setActiveCell(start);\n });\n };\n const handleMouseOverOnRowHeader = (rowIndex: number) => {\n batch(() => {\n if (!isMouseDown() || selectionMode() !== \"row\") return;\n\n const start = selectionAnchor();\n if (start) {\n const end: CellPosition = { row: rowIndex, col: numCols() - 1 };\n setSelection(normalizeRange(start, end));\n } else {\n console.warn(\"selectionAnchor is null during mouse drag selection\");\n }\n });\n };\n\n const handleMouseDownOnColHeader = (colIndex: number) => {\n if (numRows() === 0) {\n return;\n }\n\n batch(() => {\n disableTextSelectionDuringDrag();\n setIsMouseDown(true);\n setSelectionMode(\"col\");\n const start: CellPosition = { row: 0, col: colIndex };\n const end: CellPosition = { row: numRows() - 1, col: colIndex };\n setSelectionAnchor(start);\n\n setIsEditing(false);\n setSelection(normalizeRange(start, end));\n setActiveCell(start);\n });\n };\n const handleMouseOverOnColHeader = (colIndex: number) => {\n batch(() => {\n if (!isMouseDown() || selectionMode() !== \"col\") return;\n\n const start = selectionAnchor();\n if (start) {\n const end: CellPosition = { row: numRows() - 1, col: colIndex };\n setSelection(normalizeRange(start, end));\n } else {\n console.warn(\"selectionAnchor is null during mouse drag selection\");\n }\n });\n };\n\n const handleClickOnCorner = () => {\n if (numCols() === 0 || numRows() === 0) {\n return;\n }\n\n batch(() => {\n setIsEditing(false);\n setSelection(\n normalizeRange(\n { row: 0, col: 0 },\n { row: numRows() - 1, col: numCols() - 1 },\n ),\n );\n setActiveCell({ row: 0, col: 0 });\n });\n };\n\n const navigate = (\n deltaRow: number,\n deltaCol: number,\n isSelection: boolean,\n ) => {\n const ac = activeCell();\n if (!ac) return;\n\n if (isSelection) {\n let anchor = selectionAnchor();\n if (!anchor) {\n anchor = ac;\n setSelectionAnchor(anchor);\n }\n\n const sel = selection();\n let headRow = anchor.row;\n let headCol = anchor.col;\n\n if (sel) {\n headRow = sel.min.row === anchor.row ? sel.max.row : sel.min.row;\n headCol = sel.min.col === anchor.col ? sel.max.col : sel.min.col;\n }\n\n const nextHeadRow = Math.max(\n 0,\n Math.min(numRows() - 1, headRow + deltaRow),\n );\n const nextHeadCol = Math.max(\n 0,\n Math.min(numCols() - 1, headCol + deltaCol),\n );\n\n setSelection(\n normalizeRange(anchor, { row: nextHeadRow, col: nextHeadCol }),\n );\n } else {\n const nextRow = Math.max(0, Math.min(numRows() - 1, ac.row + deltaRow));\n const nextCol = Math.max(0, Math.min(numCols() - 1, ac.col + deltaCol));\n const nextPos = { row: nextRow, col: nextCol };\n\n setActiveCell(nextPos);\n setSelection(normalizeRange(nextPos, nextPos));\n setSelectionAnchor(null);\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.isComposing) return;\n\n // 編集中のキー操作はrenderCell側で処理する\n if (isEditing()) return;\n\n const ac = activeCell();\n if (!ac) return;\n\n switch (e.key) {\n case \"ArrowUp\":\n e.preventDefault();\n navigate(-1, 0, e.shiftKey);\n break;\n case \"ArrowDown\":\n e.preventDefault();\n navigate(1, 0, e.shiftKey);\n break;\n case \"ArrowLeft\":\n e.preventDefault();\n navigate(0, -1, e.shiftKey);\n break;\n case \"ArrowRight\":\n e.preventDefault();\n navigate(0, 1, e.shiftKey);\n break;\n case \"Tab\":\n e.preventDefault();\n navigate(0, e.shiftKey ? -1 : 1, false);\n break;\n case \"Enter\":\n e.preventDefault();\n beginCellEdit(ac);\n break;\n\n default:\n break;\n }\n };\n\n const cellRefs = new Map<string, HTMLElement>();\n const getCellKey = (pos: CellPosition) => `${pos.row}:${pos.col}`;\n createEffect(() => {\n if (isEditing()) return;\n const ac = activeCell();\n if (ac) {\n const el = cellRefs.get(getCellKey(ac));\n el?.focus();\n }\n });\n\n return (\n <table\n data-slot=\"gridsheet\"\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n ref={props.ref}\n class={props.class}\n style={props.style}\n >\n <thead data-slot=\"gridsheet-header\" class={props.classes?.header}>\n <tr data-slot=\"gridsheet-row\">\n <th\n data-slot=\"gridsheet-corner\"\n onClick={handleClickOnCorner}\n class={props.classes?.corner}\n ></th>\n <Index each={Array.from({ length: numCols() })}>\n {(_, colIndex) => (\n <ColHeader\n index={colIndex}\n isSelected={isColHeaderSelected(colIndex)}\n onMouseDown={handleMouseDownOnColHeader}\n onMouseOver={handleMouseOverOnColHeader}\n class={props.classes?.colHeader}\n />\n )}\n </Index>\n </tr>\n </thead>\n <tbody data-slot=\"gridsheet-body\" class={props.classes?.body}>\n <For each={props.data}>\n {(row, rowIndex) => (\n <tr\n data-slot=\"gridsheet-row\"\n class={\n typeof props.classes?.row === \"function\"\n ? props.classes?.row({ rowIndex: rowIndex() })\n : props.classes?.row\n }\n >\n <RowHeader\n index={rowIndex()}\n isSelected={isRowHeaderSelected(rowIndex())}\n onMouseDown={handleMouseDownOnRowHeader}\n onMouseOver={handleMouseOverOnRowHeader}\n class={props.classes?.rowHeader}\n />\n <For each={row}>\n {(cell, colIndex) => (\n <Cell\n row={rowIndex()}\n col={colIndex()}\n value={cell}\n isActive={isCellActive({\n row: rowIndex(),\n col: colIndex(),\n })}\n isEditing={isCellEditing({\n row: rowIndex(),\n col: colIndex(),\n })}\n isSelected={isCellSelected({\n row: rowIndex(),\n col: colIndex(),\n })}\n beginEdit={beginCellEdit}\n commitEdit={commitCellEdit}\n cancelEditing={cancelCellEdit}\n setActiveCell={setActiveCell}\n setSelection={setSelection}\n renderCell={props.renderCell}\n onMouseDown={handleMouseDownOnCell}\n onMouseOver={handleMouseOverOnCell}\n registerCellRef={(rowPos, colPos, el) => {\n cellRefs.set(\n getCellKey({ row: rowPos, col: colPos }),\n el,\n );\n }}\n class={props.classes?.cell}\n />\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n );\n}\n\ninterface RowHeaderProps {\n index: number;\n isSelected: boolean;\n\n onMouseDown: (rowIndex: number) => void;\n onMouseOver: (rowIndex: number) => void;\n\n class?: string | ((ctx: { rowIndex: number; isSelected: boolean }) => string);\n}\n\nfunction getRowLabel(rowIndex: number): string {\n return `${rowIndex + 1}`;\n}\n\nfunction RowHeader(props: RowHeaderProps) {\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: 親のtableでキー操作を処理している\n <th\n data-slot=\"gridsheet-rowheader\"\n onMouseDown={() => props.onMouseDown(props.index)}\n onMouseOver={() => props.onMouseOver(props.index)}\n class={\n typeof props.class === \"function\"\n ? props.class({ rowIndex: props.index, isSelected: props.isSelected })\n : props.class\n }\n data-selected={props.isSelected || undefined}\n >\n {getRowLabel(props.index)}\n </th>\n );\n}\n\ninterface ColHeaderProps {\n index: number;\n isSelected: boolean;\n\n onMouseDown: (colIndex: number) => void;\n onMouseOver: (colIndex: number) => void;\n\n class?: string | ((ctx: { colIndex: number; isSelected: boolean }) => string);\n}\n\nconst ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nfunction getColLabel(colIndex: number): string {\n let label = \"\";\n let n = colIndex + 1;\n while (n > 0) {\n const rem = (n - 1) % 26;\n label = ALPHABET[rem] + label;\n n = Math.floor((n - 1) / 26);\n }\n return label;\n}\n\nfunction ColHeader(props: ColHeaderProps) {\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: 親のtableでキー操作を処理している\n <th\n data-slot=\"gridsheet-colheader\"\n onMouseDown={() => props.onMouseDown(props.index)}\n onMouseOver={() => props.onMouseOver(props.index)}\n class={\n typeof props.class === \"function\"\n ? props.class({ colIndex: props.index, isSelected: props.isSelected })\n : props.class\n }\n data-selected={props.isSelected || undefined}\n >\n {getColLabel(props.index)}\n </th>\n );\n}\n\ninterface CellProps<T> {\n row: number;\n col: number;\n value: T;\n\n isSelected: boolean;\n isActive: boolean;\n isEditing: boolean;\n\n beginEdit: (pos: CellPosition) => void;\n commitEdit: (pos: CellPosition, value: T) => void;\n cancelEditing: () => void;\n\n setActiveCell?: (pos: CellPosition) => void;\n setSelection?: (range: CellRange | null) => void;\n\n onMouseDown: (pos: CellPosition, e: MouseEvent) => void;\n onMouseOver: (pos: CellPosition, e: MouseEvent) => void;\n\n registerCellRef: (row: number, col: number, el: HTMLTableCellElement) => void;\n\n renderCell: (ctx: CellRenderContext<T>) => JSX.Element;\n\n class?: string | ((ctx: CellRenderContext<T>) => string);\n}\n\nfunction Cell<T>(props: CellProps<T>) {\n let cellRef!: HTMLTableCellElement;\n\n const beginEdit = () => props.beginEdit({ row: props.row, col: props.col });\n const commitEdit = (value: T) => {\n props.commitEdit({ row: props.row, col: props.col }, value);\n };\n const cancelEditing = () => props.cancelEditing();\n\n const handleMouseDown = (e: MouseEvent) => {\n props.onMouseDown({ row: props.row, col: props.col }, e);\n };\n const handleMouseOver = (e: MouseEvent) => {\n props.onMouseOver({ row: props.row, col: props.col }, e);\n };\n const handleDoubleClick = (e: MouseEvent) => {\n if (e.button !== 0) return;\n e.preventDefault();\n if (!props.isEditing) {\n beginEdit();\n }\n };\n\n const className = createMemo(() => {\n if (typeof props.class === \"function\") {\n return props.class({\n row: props.row,\n col: props.col,\n value: props.value,\n isSelected: props.isSelected,\n isActive: props.isActive,\n isEditing: props.isEditing,\n cellRef,\n beginEdit,\n commitEdit,\n cancelEditing,\n });\n } else {\n return props.class;\n }\n });\n\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: 親のtableでキー操作を処理している\n <td\n data-slot=\"gridsheet-cell\"\n ref={(el) => {\n cellRef = el;\n props.registerCellRef(props.row, props.col, el);\n }}\n onMouseDown={handleMouseDown}\n onMouseOver={handleMouseOver}\n onDblClick={handleDoubleClick}\n tabIndex={-1}\n class={className()}\n data-row={props.row}\n data-col={props.col}\n data-selected={props.isSelected || undefined}\n data-active={props.isActive || undefined}\n data-editing={props.isEditing || undefined}\n >\n {props.renderCell({\n row: props.row,\n col: props.col,\n value: props.value,\n\n cellRef: cellRef,\n\n isSelected: props.isSelected,\n isActive: props.isActive,\n isEditing: props.isEditing,\n\n beginEdit,\n commitEdit,\n cancelEditing,\n })}\n </td>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["onEvent: GridEventHandler<T>","patches: CellPatch<T>[]","result: T[][]","row: T[]","patches: CellPatch<T>[]","clipboard: ClipboardData<T> | null","patches: CellPatch<T>[]","anchor: CellPosition | null","head: CellPosition | null","headerMode: \"row\" | \"col\" | null","previousBodyUserSelect: string | null"],"sources":["../src/gridsheet.tsx","../src/plugin.ts","../src/plugins/utils.ts","../src/plugins/clipboard-memory.ts","../src/plugins/clipboard-text.ts","../src/plugins/delete.ts","../src/plugins/editing.ts","../src/utils.ts","../src/plugins/selection.ts"],"sourcesContent":["import {\n batch,\n createEffect,\n createMemo,\n createSignal,\n For,\n Index,\n onCleanup,\n onMount,\n} from \"solid-js\";\nimport type { JSX } from \"solid-js/jsx-runtime\";\n\n/** Zero-based cell position. */\nexport type CellPosition = {\n row: number;\n col: number;\n};\n\n/** Inclusive range of cells. */\nexport type CellRange = {\n min: CellPosition;\n max: CellPosition;\n};\n\nfunction isPositionInRange(pos: CellPosition, range: CellRange): boolean {\n return (\n pos.row >= range.min.row &&\n pos.row <= range.max.row &&\n pos.col >= range.min.col &&\n pos.col <= range.max.col\n );\n}\n\n/** Normalize two positions into an inclusive range. */\nexport function normalizeRange(\n pos1: CellPosition,\n pos2: CellPosition,\n): CellRange {\n return {\n min: {\n row: Math.min(pos1.row, pos2.row),\n col: Math.min(pos1.col, pos2.col),\n },\n max: {\n row: Math.max(pos1.row, pos2.row),\n col: Math.max(pos1.col, pos2.col),\n },\n };\n}\n\n/** Render-time context for a single cell. */\nexport interface CellRenderContext<T> {\n row: number;\n col: number;\n value: T;\n\n isActive: boolean;\n isSelected: boolean;\n isEditing: boolean;\n\n cellRef: HTMLTableCellElement | undefined;\n\n beginEdit: () => void;\n commitEdit: (value: T) => void;\n cancelEditing: () => void;\n}\n\n/** Events emitted from Gridsheet to plugins/handlers. */\nexport type GridEvent =\n | { type: \"cell:pointerdown\"; pos: CellPosition; e: MouseEvent }\n | { type: \"cell:pointerover\"; pos: CellPosition; e: MouseEvent }\n | { type: \"cell:dblclick\"; pos: CellPosition; e: MouseEvent }\n | { type: \"key:down\"; e: KeyboardEvent }\n | { type: \"corner:click\"; e: MouseEvent }\n | { type: \"rowheader:pointerdown\"; row: number; e: MouseEvent }\n | { type: \"rowheader:pointerover\"; row: number; e: MouseEvent }\n | { type: \"colheader:pointerdown\"; col: number; e: MouseEvent }\n | { type: \"colheader:pointerover\"; col: number; e: MouseEvent }\n | { type: \"pointer:up\"; e: PointerEvent | MouseEvent };\n\n/** Return true to stop further handling. */\nexport type GridEventHandler<T> = (\n ev: GridEvent,\n api: GridApi<T>,\n) => boolean | undefined;\n\n/** Props for the Gridsheet component. */\nexport interface GridsheetProps<T> {\n data: T[][];\n /** Apply patches to external data store. */\n onCellsChange?: (patches: CellPatch<T>[]) => void;\n\n renderCell: (ctx: CellRenderContext<T>) => JSX.Element;\n renderRowHeader?: (ctx: {\n index: number;\n isSelected: boolean;\n }) => JSX.Element;\n renderColHeader?: (ctx: {\n index: number;\n isSelected: boolean;\n }) => JSX.Element;\n\n activeCell?: CellPosition | null;\n onActiveCellChange?: (pos: CellPosition | null) => void;\n\n selection?: CellRange | null;\n onSelectionChange?: (range: CellRange | null) => void;\n\n isEditing?: boolean;\n onIsEditingChange?: (isEditing: boolean) => void;\n\n /**\n * 本体は仕様を持たず “イベントを投げる” のが仕事。\n * 既定の挙動は plugin 側で組み立てる\n */\n onEvent?: GridEventHandler<T>;\n\n ref?: HTMLTableElement | ((el: HTMLTableElement) => void) | undefined;\n class?: string;\n style?: JSX.CSSProperties | string;\n classes?: {\n cell?: string | ((ctx: CellRenderContext<T>) => string);\n row?: string | ((ctx: { rowIndex: number }) => string);\n rowHeader?:\n | string\n | ((ctx: { rowIndex: number; isSelected: boolean }) => string);\n colHeader?:\n | string\n | ((ctx: { colIndex: number; isSelected: boolean }) => string);\n corner?: string;\n header?: string;\n body?: string;\n };\n}\n\nfunction createControllable<T>(\n propsValue: () => T | undefined,\n onChange?: (v: T) => void,\n initial?: T,\n) {\n const [inner, setInner] = createSignal<T>(initial as T);\n const value = createMemo(() =>\n propsValue() === undefined ? inner() : (propsValue() as T),\n );\n const set = (v: T) => {\n setInner(() => v);\n onChange?.(v);\n };\n return [value, set] as const;\n}\n\n/** Patch for a single cell update. */\nexport type CellPatch<T> = { pos: CellPosition; value: T };\n/** API exposed to plugins and external handlers. */\nexport type GridApi<T> = {\n // state readers\n numRows: () => number;\n numCols: () => number;\n activeCell: () => CellPosition | null;\n selection: () => CellRange | null;\n isEditing: () => boolean;\n\n // commands\n setActiveCell: (pos: CellPosition | null) => void;\n setSelection: (range: CellRange | null) => void;\n beginEdit: (pos: CellPosition) => void;\n cancelEdit: () => void;\n commitEdit: (pos: CellPosition, value: T) => void;\n\n updateCells: (patches: CellPatch<T>[]) => void;\n};\n\nfunction createGridApi<T>(props: GridsheetProps<T>): GridApi<T> {\n const numRows = createMemo(() => props.data.length);\n const numCols = createMemo(() => props.data[0]?.length ?? 0);\n\n const [activeCell, setActiveCell] = createControllable<CellPosition | null>(\n () => props.activeCell,\n props.onActiveCellChange,\n null,\n );\n\n const [selection, setSelectionRaw] = createControllable<CellRange | null>(\n () => props.selection,\n props.onSelectionChange,\n null,\n );\n\n const setSelection = (range: CellRange | null) => {\n setSelectionRaw(range ? normalizeRange(range.min, range.max) : null);\n };\n\n const [isEditing, setIsEditing] = createControllable<boolean>(\n () => props.isEditing,\n props.onIsEditingChange,\n false,\n );\n\n const updateCells = (patches: CellPatch<T>[]) => {\n props.onCellsChange?.(patches);\n };\n\n const beginEdit = (pos: CellPosition) => {\n batch(() => {\n setIsEditing(true);\n setActiveCell(pos);\n setSelection(normalizeRange(pos, pos));\n });\n };\n\n const cancelEdit = () => setIsEditing(false);\n\n const commitEdit = (pos: CellPosition, value: T) => {\n updateCells([{ pos, value }]);\n setIsEditing(false);\n };\n\n return {\n numRows,\n numCols,\n activeCell,\n selection,\n isEditing,\n\n setActiveCell,\n setSelection,\n beginEdit,\n cancelEdit,\n commitEdit,\n\n updateCells,\n };\n}\n\nexport function Gridsheet<T>(props: GridsheetProps<T>): JSX.Element {\n const api = createGridApi(props);\n\n const emit = (ev: GridEvent) => {\n props.onEvent?.(ev, api);\n };\n\n const isCellActive = (pos: CellPosition) => {\n const ac = api.activeCell();\n return ac !== null && ac.row === pos.row && ac.col === pos.col;\n };\n\n const isCellSelected = (pos: CellPosition) => {\n const sel = api.selection();\n return sel !== null && isPositionInRange(pos, sel);\n };\n\n const isRowHeaderSelected = (rowIndex: number) => {\n const sel = api.selection();\n return sel !== null && rowIndex >= sel.min.row && rowIndex <= sel.max.row;\n };\n\n const isColHeaderSelected = (colIndex: number) => {\n const sel = api.selection();\n return sel !== null && colIndex >= sel.min.col && colIndex <= sel.max.col;\n };\n\n const renderRowHeader = props.renderRowHeader ?? defaultRenderRowHeader;\n const renderColHeader = props.renderColHeader ?? defaultRenderColHeader;\n\n const isCellEditing = (pos: CellPosition) =>\n api.isEditing() && isCellActive(pos);\n\n const cellRefs = new Map<string, HTMLElement>();\n const getCellKey = (pos: CellPosition) => `${pos.row}:${pos.col}`;\n createEffect(() => {\n if (api.isEditing()) return;\n const ac = api.activeCell();\n if (!ac) return;\n const el = cellRefs.get(getCellKey(ac));\n el?.focus();\n });\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.isComposing) return;\n // 編集中のキー操作は renderCell 側に委ねる\n if (api.isEditing()) return;\n emit({ type: \"key:down\", e });\n };\n\n const onUp = (e: PointerEvent | MouseEvent) =>\n emit({ type: \"pointer:up\", e });\n onMount(() => {\n window.addEventListener(\"pointerup\", onUp);\n });\n onCleanup(() => {\n window.removeEventListener(\"pointerup\", onUp);\n });\n\n return (\n <table\n data-slot=\"gridsheet\"\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n ref={props.ref}\n class={props.class}\n style={props.style}\n >\n <thead data-slot=\"gridsheet-header\" class={props.classes?.header}>\n <tr data-slot=\"gridsheet-row\">\n <th\n data-slot=\"gridsheet-corner\"\n onClick={(e) => emit({ type: \"corner:click\", e })}\n class={props.classes?.corner}\n ></th>\n\n <Index each={Array.from({ length: api.numCols() })}>\n {(_, colIndex) => (\n <ColHeader\n index={colIndex}\n isSelected={isColHeaderSelected(colIndex)}\n onMouseDown={(col, e) =>\n emit({ type: \"colheader:pointerdown\", col, e })\n }\n onMouseOver={(col, e) =>\n emit({ type: \"colheader:pointerover\", col, e })\n }\n class={props.classes?.colHeader}\n renderHeader={renderColHeader}\n />\n )}\n </Index>\n </tr>\n </thead>\n\n <tbody data-slot=\"gridsheet-body\" class={props.classes?.body}>\n <For each={props.data}>\n {(row, rowIndex) => (\n <tr\n data-slot=\"gridsheet-row\"\n class={\n typeof props.classes?.row === \"function\"\n ? props.classes?.row({ rowIndex: rowIndex() })\n : props.classes?.row\n }\n >\n <RowHeader\n index={rowIndex()}\n isSelected={isRowHeaderSelected(rowIndex())}\n onMouseDown={(r, e) =>\n emit({ type: \"rowheader:pointerdown\", row: r, e })\n }\n onMouseOver={(r, e) =>\n emit({ type: \"rowheader:pointerover\", row: r, e })\n }\n class={props.classes?.rowHeader}\n renderHeader={renderRowHeader}\n />\n\n <For each={row}>\n {(cell, colIndex) => (\n <Cell\n row={rowIndex()}\n col={colIndex()}\n value={cell}\n isActive={isCellActive({\n row: rowIndex(),\n col: colIndex(),\n })}\n isEditing={isCellEditing({\n row: rowIndex(),\n col: colIndex(),\n })}\n isSelected={isCellSelected({\n row: rowIndex(),\n col: colIndex(),\n })}\n beginEdit={(pos) => api.beginEdit(pos)}\n commitEdit={(pos, value) => api.commitEdit(pos, value)}\n cancelEditing={() => api.cancelEdit()}\n renderCell={props.renderCell}\n onMouseDown={(pos, e) =>\n emit({ type: \"cell:pointerdown\", pos, e })\n }\n onMouseOver={(pos, e) =>\n emit({ type: \"cell:pointerover\", pos, e })\n }\n onDoubleClick={(pos, e) =>\n emit({ type: \"cell:dblclick\", pos, e })\n }\n registerCellRef={(r, c, el) => {\n cellRefs.set(getCellKey({ row: r, col: c }), el);\n }}\n class={props.classes?.cell}\n />\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n );\n}\n\ninterface RowHeaderProps {\n index: number;\n isSelected: boolean;\n onMouseDown: (rowIndex: number, e: MouseEvent) => void;\n onMouseOver: (rowIndex: number, e: MouseEvent) => void;\n class?: string | ((ctx: { rowIndex: number; isSelected: boolean }) => string);\n renderHeader: (ctx: { index: number; isSelected: boolean }) => JSX.Element;\n}\n\nfunction getRowLabel(rowIndex: number): string {\n return `${rowIndex + 1}`;\n}\n\nfunction defaultRenderRowHeader(ctx: { index: number; isSelected: boolean }) {\n return <>{getRowLabel(ctx.index)}</>;\n}\n\nfunction RowHeader(props: RowHeaderProps) {\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: header drag selection is mouse-only\n <th\n data-slot=\"gridsheet-rowheader\"\n onMouseDown={(e) => props.onMouseDown(props.index, e)}\n onMouseOver={(e) => props.onMouseOver(props.index, e)}\n class={\n typeof props.class === \"function\"\n ? props.class({ rowIndex: props.index, isSelected: props.isSelected })\n : props.class\n }\n data-selected={props.isSelected || undefined}\n >\n {props.renderHeader({ index: props.index, isSelected: props.isSelected })}\n </th>\n );\n}\n\ninterface ColHeaderProps {\n index: number;\n isSelected: boolean;\n onMouseDown: (colIndex: number, e: MouseEvent) => void;\n onMouseOver: (colIndex: number, e: MouseEvent) => void;\n class?: string | ((ctx: { colIndex: number; isSelected: boolean }) => string);\n renderHeader: (ctx: { index: number; isSelected: boolean }) => JSX.Element;\n}\n\nconst ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nfunction getColLabel(colIndex: number): string {\n let label = \"\";\n let n = colIndex + 1;\n while (n > 0) {\n const rem = (n - 1) % 26;\n label = ALPHABET[rem] + label;\n n = Math.floor((n - 1) / 26);\n }\n return label;\n}\n\nfunction defaultRenderColHeader(ctx: { index: number; isSelected: boolean }) {\n return <>{getColLabel(ctx.index)}</>;\n}\n\nfunction ColHeader(props: ColHeaderProps) {\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: header drag selection is mouse-only\n <th\n data-slot=\"gridsheet-colheader\"\n onMouseDown={(e) => props.onMouseDown(props.index, e)}\n onMouseOver={(e) => props.onMouseOver(props.index, e)}\n class={\n typeof props.class === \"function\"\n ? props.class({ colIndex: props.index, isSelected: props.isSelected })\n : props.class\n }\n data-selected={props.isSelected || undefined}\n >\n {props.renderHeader({ index: props.index, isSelected: props.isSelected })}\n </th>\n );\n}\n\ninterface CellProps<T> {\n row: number;\n col: number;\n value: T;\n\n isSelected: boolean;\n isActive: boolean;\n isEditing: boolean;\n\n beginEdit: (pos: CellPosition) => void;\n commitEdit: (pos: CellPosition, value: T) => void;\n cancelEditing: () => void;\n\n onMouseDown: (pos: CellPosition, e: MouseEvent) => void;\n onMouseOver: (pos: CellPosition, e: MouseEvent) => void;\n onDoubleClick: (pos: CellPosition, e: MouseEvent) => void;\n\n registerCellRef: (row: number, col: number, el: HTMLTableCellElement) => void;\n\n renderCell: (ctx: CellRenderContext<T>) => JSX.Element;\n\n class?: string | ((ctx: CellRenderContext<T>) => string);\n}\n\nfunction Cell<T>(props: CellProps<T>) {\n let cellRef!: HTMLTableCellElement;\n\n const beginEdit = () => props.beginEdit({ row: props.row, col: props.col });\n const commitEdit = (value: T) =>\n props.commitEdit({ row: props.row, col: props.col }, value);\n const cancelEditing = () => props.cancelEditing();\n\n const className = createMemo(() => {\n if (typeof props.class === \"function\") {\n return props.class({\n row: props.row,\n col: props.col,\n value: props.value,\n isSelected: props.isSelected,\n isActive: props.isActive,\n isEditing: props.isEditing,\n cellRef,\n beginEdit,\n commitEdit,\n cancelEditing,\n });\n }\n return props.class;\n });\n\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: 親のtableでキー操作を処理している\n <td\n data-slot=\"gridsheet-cell\"\n ref={(el) => {\n cellRef = el;\n props.registerCellRef(props.row, props.col, el);\n }}\n onMouseDown={(e) =>\n props.onMouseDown({ row: props.row, col: props.col }, e)\n }\n onMouseOver={(e) =>\n props.onMouseOver({ row: props.row, col: props.col }, e)\n }\n onDblClick={(e) =>\n props.onDoubleClick({ row: props.row, col: props.col }, e)\n }\n tabIndex={-1}\n class={className()}\n data-row={props.row}\n data-col={props.col}\n data-selected={props.isSelected || undefined}\n data-active={props.isActive || undefined}\n data-editing={props.isEditing || undefined}\n >\n {props.renderCell({\n row: props.row,\n col: props.col,\n value: props.value,\n\n cellRef,\n\n isSelected: props.isSelected,\n isActive: props.isActive,\n isEditing: props.isEditing,\n\n beginEdit,\n commitEdit,\n cancelEditing,\n })}\n </td>\n );\n}\n","import type { GridApi, GridEvent, GridEventHandler } from \"./gridsheet\";\n\n/** Plugin interface for extending grid behavior. */\nexport type GridPlugin<T> = {\n name: string;\n onEvent?: GridEventHandler<T>;\n};\n\n/** Compose multiple plugins into a single event handler. */\nexport function createPluginHost<T>(plugins: GridPlugin<T>[]) {\n // Plugins are executed in order; first plugin to return true stops propagation.\n const onEvent: GridEventHandler<T> = (ev: GridEvent, api: GridApi<T>) => {\n for (const p of plugins) {\n const handled = p.onEvent?.(ev, api);\n if (handled === true) return true;\n }\n return false;\n };\n\n return { onEvent };\n}\n","import type { CellPatch, CellPosition, CellRange } from \"../gridsheet\";\n\nexport function buildClearPatches<T>(\n range: CellRange,\n getEmptyValue: (pos: CellPosition) => T,\n): CellPatch<T>[] {\n const patches: CellPatch<T>[] = [];\n for (let r = range.min.row; r <= range.max.row; r++) {\n for (let c = range.min.col; c <= range.max.col; c++) {\n const pos = { row: r, col: c };\n patches.push({ pos, value: getEmptyValue(pos) });\n }\n }\n return patches;\n}\n","import type { CellPatch, CellPosition, CellRange } from \"../gridsheet\";\nimport type { GridPlugin } from \"../plugin\";\nimport { buildClearPatches } from \"./utils\";\n\nexport type ClipboardData<T> = {\n data: T[][];\n range: CellRange;\n};\n\n/** Options for in-memory clipboard behavior. */\nexport type ClipboardPluginOptions<T> = {\n getData: () => T[][];\n onCopy?: (\n data: T[][],\n range: CellRange,\n ) => boolean | undefined | Promise<boolean | undefined>;\n onCut?: (\n data: T[][],\n range: CellRange,\n ) => boolean | undefined | Promise<boolean | undefined>;\n onPaste?: (\n clipboardData: T[][],\n targetPosition: CellPosition,\n ) =>\n | CellPatch<T>[]\n | false\n | undefined\n | Promise<CellPatch<T>[] | false | undefined>;\n onClipboardChange?: (clipboard: ClipboardData<T> | null) => void;\n emptyValue?: T;\n getEmptyValue?: (pos: CellPosition) => T;\n copyKeys?: string[];\n cutKeys?: string[];\n pasteKeys?: string[];\n};\n\nfunction extractSelection<T>(data: T[][], range: CellRange): T[][] {\n const result: T[][] = [];\n for (let r = range.min.row; r <= range.max.row; r++) {\n const row: T[] = [];\n for (let c = range.min.col; c <= range.max.col; c++) {\n const rowData = data[r];\n if (rowData && c < rowData.length) {\n const value = rowData[c];\n if (value !== undefined) {\n row.push(value);\n }\n }\n }\n result.push(row);\n }\n return result;\n}\n\nfunction buildPastePatches<T>(\n data: T[][],\n start: CellPosition,\n rows: number,\n cols: number,\n): CellPatch<T>[] {\n const patches: CellPatch<T>[] = [];\n for (let r = 0; r < data.length; r++) {\n const row = data[r];\n if (!row) continue;\n for (let c = 0; c < row.length; c++) {\n const targetRow = start.row + r;\n const targetCol = start.col + c;\n if (targetRow < 0 || targetCol < 0) continue;\n if (targetRow >= rows || targetCol >= cols) continue;\n const value = row[c];\n if (value === undefined) continue;\n patches.push({ pos: { row: targetRow, col: targetCol }, value });\n }\n }\n return patches;\n}\n\n/** In-memory clipboard with optional cut clearing. */\nexport function clipboardMemoryPlugin<T>(\n options: ClipboardPluginOptions<T>,\n): GridPlugin<T> {\n let clipboard: ClipboardData<T> | null = null;\n const copyKeys = options.copyKeys ?? [\"c\"];\n const cutKeys = options.cutKeys ?? [\"x\"];\n const pasteKeys = options.pasteKeys ?? [\"v\"];\n const getEmptyValue =\n options.getEmptyValue ??\n (options.emptyValue !== undefined ? () => options.emptyValue as T : null);\n\n const setClipboard = (next: ClipboardData<T> | null) => {\n clipboard = next;\n options.onClipboardChange?.(next);\n };\n\n return {\n name: \"clipboard-memory\",\n onEvent(ev, api) {\n if (ev.type !== \"key:down\") return;\n const e = ev.e;\n if (e.isComposing || api.isEditing()) return;\n\n const key = e.key.toLowerCase();\n const isCopy = (e.ctrlKey || e.metaKey) && copyKeys.includes(key);\n const isCut = (e.ctrlKey || e.metaKey) && cutKeys.includes(key);\n const isPaste = (e.ctrlKey || e.metaKey) && pasteKeys.includes(key);\n if (!isCopy && !isCut && !isPaste) return;\n\n const sel = api.selection();\n const ac = api.activeCell();\n\n if (isCopy || isCut) {\n if (!sel) return true;\n e.preventDefault();\n void (async () => {\n const copiedData = extractSelection(options.getData(), sel);\n const result = isCopy\n ? await options.onCopy?.(copiedData, sel)\n : await options.onCut?.(copiedData, sel);\n if (result === false) return;\n setClipboard({ data: copiedData, range: sel });\n if (isCut && getEmptyValue) {\n const patches = buildClearPatches(sel, getEmptyValue);\n if (patches.length > 0) {\n api.updateCells(patches);\n }\n }\n })();\n return true;\n }\n\n if (isPaste) {\n if (!ac || !clipboard) return true;\n e.preventDefault();\n void (async () => {\n const result = await options.onPaste?.(clipboard.data, ac);\n if (result === false) return;\n const patches =\n result ??\n buildPastePatches(clipboard.data, ac, api.numRows(), api.numCols());\n if (patches.length > 0) {\n api.updateCells(patches);\n }\n })();\n return true;\n }\n },\n };\n}\n","import type { CellPatch, CellPosition } from \"../gridsheet\";\nimport type { GridPlugin } from \"../plugin\";\nimport { buildClearPatches } from \"./utils\";\n\n/** Options for system clipboard text/TSV behavior. */\nexport type ClipboardTextPluginOptions<T> = {\n getData: () => T[][];\n toText?: (data: T[][]) => string;\n fromText?: (text: string, target: CellPosition) => CellPatch<T>[] | false;\n parseCell?: (raw: string) => T;\n formatCell?: (value: T) => string;\n readText?: () => Promise<string>;\n writeText?: (text: string) => Promise<void>;\n emptyValue?: T;\n getEmptyValue?: (pos: CellPosition) => T;\n copyKeys?: string[];\n cutKeys?: string[];\n pasteKeys?: string[];\n};\n\nconst DEFAULT_COPY_KEYS = [\"c\"];\nconst DEFAULT_CUT_KEYS = [\"x\"];\nconst DEFAULT_PASTE_KEYS = [\"v\"];\n\nfunction defaultReadText(): Promise<string> {\n if (typeof navigator === \"undefined\" || !navigator.clipboard) {\n return Promise.resolve(\"\");\n }\n return navigator.clipboard.readText();\n}\n\nfunction defaultWriteText(text: string): Promise<void> {\n if (typeof navigator === \"undefined\" || !navigator.clipboard) {\n return Promise.resolve();\n }\n return navigator.clipboard.writeText(text);\n}\n\nfunction serializeTsv<T>(\n data: T[][],\n formatCell: (value: T) => string,\n): string {\n return data.map((row) => row.map(formatCell).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction parseTsv<T>(\n text: string,\n target: CellPosition,\n parseCell: (raw: string) => T,\n): CellPatch<T>[] {\n const normalized = text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n const rows = normalized.split(\"\\n\");\n const patches: CellPatch<T>[] = [];\n for (let r = 0; r < rows.length; r++) {\n const cols = rows[r]?.split(\"\\t\") ?? [];\n for (let c = 0; c < cols.length; c++) {\n patches.push({\n pos: { row: target.row + r, col: target.col + c },\n value: parseCell(cols[c] ?? \"\"),\n });\n }\n }\n return patches;\n}\n\n/** System clipboard integration with TSV defaults. */\nexport function clipboardTextPlugin<T>(\n options: ClipboardTextPluginOptions<T>,\n): GridPlugin<T> {\n const copyKeys = options.copyKeys ?? DEFAULT_COPY_KEYS;\n const cutKeys = options.cutKeys ?? DEFAULT_CUT_KEYS;\n const pasteKeys = options.pasteKeys ?? DEFAULT_PASTE_KEYS;\n const parseCell = options.parseCell ?? ((raw) => raw as unknown as T);\n const formatCell = options.formatCell ?? ((value) => String(value));\n\n const toText = options.toText ?? ((data) => serializeTsv(data, formatCell));\n const fromText =\n options.fromText ?? ((text, target) => parseTsv(text, target, parseCell));\n\n const readText = options.readText ?? defaultReadText;\n const writeText = options.writeText ?? defaultWriteText;\n const getEmptyValue =\n options.getEmptyValue ??\n (options.emptyValue !== undefined ? () => options.emptyValue as T : null);\n\n return {\n name: \"clipboard-text\",\n onEvent(ev, api) {\n if (ev.type !== \"key:down\") return;\n const e = ev.e;\n if (e.isComposing || api.isEditing()) return;\n\n const key = e.key.toLowerCase();\n const isCopy = (e.ctrlKey || e.metaKey) && copyKeys.includes(key);\n const isCut = (e.ctrlKey || e.metaKey) && cutKeys.includes(key);\n const isPaste = (e.ctrlKey || e.metaKey) && pasteKeys.includes(key);\n if (!isCopy && !isCut && !isPaste) return;\n\n if (isCopy || isCut) {\n const sel = api.selection();\n if (!sel) return true;\n e.preventDefault();\n void (async () => {\n const data = options.getData();\n const rows = data.slice(sel.min.row, sel.max.row + 1);\n const selected = rows.map((row) =>\n row.slice(sel.min.col, sel.max.col + 1),\n );\n const text = toText(selected);\n await writeText(text);\n if (isCut && getEmptyValue) {\n const patches = buildClearPatches(sel, getEmptyValue);\n if (patches.length > 0) {\n api.updateCells(patches);\n }\n }\n })();\n return true;\n }\n\n if (isPaste) {\n const ac = api.activeCell();\n if (!ac) return true;\n e.preventDefault();\n void (async () => {\n const text = await readText();\n if (!text) return;\n const patches = fromText(text, ac);\n if (patches === false) return;\n if (patches.length > 0) {\n api.updateCells(patches);\n }\n })();\n return true;\n }\n },\n };\n}\n","import type { CellPatch, CellPosition, CellRange } from \"../gridsheet\";\nimport type { GridPlugin } from \"../plugin\";\nimport { buildClearPatches } from \"./utils\";\n\n/** Options for delete behavior. */\nexport type DeletePluginOptions<T> = {\n keys?: string[];\n emptyValue?: T;\n getEmptyValue?: (pos: CellPosition) => T;\n onDelete?: (range: CellRange) => CellPatch<T>[] | false | undefined;\n};\n\n/** Clears selected range with provided empty values. */\nexport function deletePlugin<T>(\n options: DeletePluginOptions<T>,\n): GridPlugin<T> {\n const keys = options.keys ?? [\"Delete\", \"Backspace\"];\n const getEmptyValue =\n options.getEmptyValue ??\n (options.emptyValue !== undefined ? () => options.emptyValue as T : null);\n\n return {\n name: \"delete\",\n onEvent(ev, api) {\n if (ev.type !== \"key:down\") return;\n const e = ev.e;\n if (e.isComposing || api.isEditing()) return;\n if (!keys.includes(e.key)) return;\n\n const range = api.selection();\n if (!range) {\n e.preventDefault();\n return true;\n }\n\n const result = options.onDelete?.(range);\n if (result === false) {\n e.preventDefault();\n return true;\n }\n if (Array.isArray(result)) {\n api.updateCells(result);\n e.preventDefault();\n return true;\n }\n\n if (getEmptyValue) {\n const patches = buildClearPatches(range, getEmptyValue);\n if (patches.length > 0) {\n api.updateCells(patches);\n }\n e.preventDefault();\n return true;\n }\n\n return true;\n },\n };\n}\n","import type { GridPlugin } from \"../plugin\";\n\ntype EditingPluginOptions = {\n triggerKeys?: string[];\n};\n\n/** Starts editing via double click or configured keys. */\nexport function editingPlugin<T>(\n options: EditingPluginOptions = {},\n): GridPlugin<T> {\n const triggerKeys = options.triggerKeys ?? [\"Enter\"];\n return {\n name: \"editing\",\n onEvent(ev, api) {\n if (ev.type === \"cell:dblclick\") {\n if (api.isEditing()) return true;\n api.beginEdit(ev.pos);\n return true;\n }\n\n if (ev.type === \"key:down\") {\n const e = ev.e;\n if (e.isComposing || api.isEditing()) return;\n if (!triggerKeys.includes(e.key)) return;\n\n const ac = api.activeCell();\n if (!ac) return true;\n\n e.preventDefault();\n api.beginEdit(ac);\n return true;\n }\n },\n };\n}\n","export function clamp(n: number, min: number, max: number) {\n return Math.max(min, Math.min(max, n));\n}\n","import { batch } from \"solid-js\";\nimport type { CellPosition, GridApi } from \"../gridsheet\";\nimport { normalizeRange } from \"../gridsheet\";\nimport type { GridPlugin } from \"../plugin\";\nimport { clamp } from \"../utils\";\n\nfunction moveBy(\n pos: CellPosition,\n dr: number,\n dc: number,\n rows: number,\n cols: number,\n): CellPosition {\n return {\n row: clamp(pos.row + dr, 0, rows - 1),\n col: clamp(pos.col + dc, 0, cols - 1),\n };\n}\n\n/** Selection, drag, and arrow-key navigation. */\nexport function selectionPlugin<T>(): GridPlugin<T> {\n let anchor: CellPosition | null = null;\n let head: CellPosition | null = null;\n let dragging = false;\n let headerMode: \"row\" | \"col\" | null = null;\n let previousBodyUserSelect: string | null = null;\n\n const disableTextSelectionDuringDrag = () => {\n if (typeof document === \"undefined\" || previousBodyUserSelect !== null)\n return;\n const body = document.body;\n if (!body) return;\n previousBodyUserSelect = body.style.userSelect;\n body.style.userSelect = \"none\";\n };\n\n const restoreTextSelectionAfterDrag = () => {\n if (typeof document === \"undefined\" || previousBodyUserSelect === null)\n return;\n const body = document.body;\n if (body) {\n body.style.userSelect = previousBodyUserSelect;\n }\n previousBodyUserSelect = null;\n };\n const setSingle = (pos: CellPosition, api: GridApi<T>) => {\n anchor = pos;\n head = pos;\n batch(() => {\n api.setActiveCell(pos);\n api.setSelection(normalizeRange(pos, pos));\n });\n };\n\n const setRange = (\n rangeAnchor: CellPosition,\n rangeHead: CellPosition,\n api: GridApi<T>,\n ) => {\n anchor = rangeAnchor;\n head = rangeHead;\n api.setSelection(normalizeRange(rangeAnchor, rangeHead));\n };\n\n return {\n name: \"selection\",\n onEvent(ev, api) {\n switch (ev.type) {\n case \"cell:pointerdown\": {\n if (api.isEditing()) return true;\n\n // Ignore non-left clicks\n if (ev.e.button !== 0) return;\n\n ev.e.preventDefault();\n dragging = true;\n headerMode = null;\n disableTextSelectionDuringDrag();\n\n setSingle(ev.pos, api);\n return true;\n }\n\n case \"cell:pointerover\": {\n if (!dragging) return;\n // Do not treat as dragging if mouse button is not pressed\n if ((ev.e.buttons & 1) === 0) return;\n\n if (!anchor) {\n // This should not be reached\n anchor = ev.pos;\n }\n setRange(anchor, ev.pos, api);\n return true;\n }\n\n case \"pointer:up\": {\n if (dragging) dragging = false;\n headerMode = null;\n restoreTextSelectionAfterDrag();\n return;\n }\n\n case \"corner:click\": {\n const rows = api.numRows();\n const cols = api.numCols();\n if (rows <= 0 || cols <= 0) return true;\n const min = { row: 0, col: 0 };\n const max = { row: rows - 1, col: cols - 1 };\n dragging = false;\n anchor = min;\n head = max;\n batch(() => {\n api.setActiveCell(min);\n api.setSelection(normalizeRange(min, max));\n });\n return true;\n }\n\n case \"rowheader:pointerdown\": {\n const cols = api.numCols();\n if (cols <= 0) return true;\n const min = { row: ev.row, col: 0 };\n const max = { row: ev.row, col: cols - 1 };\n dragging = false;\n headerMode = \"row\";\n disableTextSelectionDuringDrag();\n anchor = min;\n head = max;\n batch(() => {\n api.setActiveCell(min);\n api.setSelection(normalizeRange(min, max));\n });\n return true;\n }\n\n case \"rowheader:pointerover\": {\n if (headerMode !== \"row\") return;\n if ((ev.e.buttons & 1) === 0) return;\n const cols = api.numCols();\n if (cols <= 0) return true;\n const startRow = anchor?.row ?? ev.row;\n const min = { row: Math.min(startRow, ev.row), col: 0 };\n const max = { row: Math.max(startRow, ev.row), col: cols - 1 };\n head = max;\n api.setSelection(normalizeRange(min, max));\n return true;\n }\n\n case \"colheader:pointerdown\": {\n const rows = api.numRows();\n if (rows <= 0) return true;\n const min = { row: 0, col: ev.col };\n const max = { row: rows - 1, col: ev.col };\n dragging = false;\n headerMode = \"col\";\n disableTextSelectionDuringDrag();\n anchor = min;\n head = max;\n batch(() => {\n api.setActiveCell(min);\n api.setSelection(normalizeRange(min, max));\n });\n return true;\n }\n\n case \"colheader:pointerover\": {\n if (headerMode !== \"col\") return;\n if ((ev.e.buttons & 1) === 0) return;\n const rows = api.numRows();\n if (rows <= 0) return true;\n const startCol = anchor?.col ?? ev.col;\n const min = { row: 0, col: Math.min(startCol, ev.col) };\n const max = { row: rows - 1, col: Math.max(startCol, ev.col) };\n head = max;\n api.setSelection(normalizeRange(min, max));\n return true;\n }\n\n case \"key:down\": {\n const e = ev.e;\n if (e.isComposing) return;\n if (api.isEditing()) return;\n\n const ac = api.activeCell();\n if (!ac) return;\n\n const key = e.key;\n const isArrow =\n key === \"ArrowUp\" ||\n key === \"ArrowDown\" ||\n key === \"ArrowLeft\" ||\n key === \"ArrowRight\";\n const isTab = key === \"Tab\";\n if (!isArrow && !isTab) return;\n\n e.preventDefault();\n\n const rows = api.numRows();\n const cols = api.numCols();\n if (rows <= 0 || cols <= 0) return true;\n\n if (isTab) {\n let next = ac;\n if (e.shiftKey) {\n if (ac.col > 0) {\n next = { row: ac.row, col: ac.col - 1 };\n } else if (ac.row > 0) {\n next = { row: ac.row - 1, col: cols - 1 };\n }\n } else if (ac.col < cols - 1) {\n next = { row: ac.row, col: ac.col + 1 };\n } else if (ac.row < rows - 1) {\n next = { row: ac.row + 1, col: 0 };\n }\n\n dragging = false;\n setSingle(next, api);\n return true;\n }\n\n const dr = key === \"ArrowUp\" ? -1 : key === \"ArrowDown\" ? 1 : 0;\n const dc = key === \"ArrowLeft\" ? -1 : key === \"ArrowRight\" ? 1 : 0;\n\n if (e.shiftKey) {\n const rangeAnchor = anchor ?? ac; // Initial shift anchor is current position\n const currentHead = head ?? ac;\n const nextHead = moveBy(currentHead, dr, dc, rows, cols);\n setRange(rangeAnchor, nextHead, api);\n } else {\n // Normal arrow: single cell move (reset anchor/head)\n const next = moveBy(ac, dr, dc, rows, cols);\n dragging = false;\n setSingle(next, api);\n }\n\n return true;\n }\n\n default:\n return;\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@source "./presets.{js,tsx}";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { i as CellRenderContext } from "./gridsheet-D9A0kuhj.js";
|
|
2
|
+
import * as solid_js0 from "solid-js";
|
|
3
|
+
|
|
4
|
+
//#region src/presets.d.ts
|
|
5
|
+
declare function textCellRenderer(ctx: CellRenderContext<string>): solid_js0.JSX.Element;
|
|
6
|
+
declare const gridsheetStyle: string;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { gridsheetStyle, textCellRenderer };
|
|
9
|
+
//# sourceMappingURL=presets.d.ts.map
|
package/dist/presets.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { delegateEvents, effect, memo, template, use } from "solid-js/web";
|
|
2
|
+
import { createEffect, createSignal } from "solid-js";
|
|
3
|
+
|
|
4
|
+
//#region src/presets.tsx
|
|
5
|
+
var _tmpl$ = /* @__PURE__ */ template(`<input data-slot=gridsheet-preset-text-input type=text>`);
|
|
6
|
+
function textCellRenderer(ctx) {
|
|
7
|
+
const [draft, setDraft] = createSignal(ctx.value);
|
|
8
|
+
createEffect(() => {
|
|
9
|
+
if (!ctx.isEditing) setDraft(ctx.value);
|
|
10
|
+
});
|
|
11
|
+
let inputRef;
|
|
12
|
+
createEffect(() => {
|
|
13
|
+
if (!inputRef) return;
|
|
14
|
+
if (ctx.isEditing) {
|
|
15
|
+
inputRef.select();
|
|
16
|
+
inputRef.focus();
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const handleCommit = () => {
|
|
20
|
+
ctx.commitEdit(draft());
|
|
21
|
+
queueMicrotask(() => ctx.cellRef?.focus());
|
|
22
|
+
};
|
|
23
|
+
const handleCancel = () => {
|
|
24
|
+
setDraft(ctx.value);
|
|
25
|
+
ctx.cancelEditing();
|
|
26
|
+
queueMicrotask(() => ctx.cellRef?.focus());
|
|
27
|
+
};
|
|
28
|
+
if (ctx.isEditing) return (() => {
|
|
29
|
+
var _el$ = _tmpl$();
|
|
30
|
+
_el$.addEventListener("blur", handleCommit);
|
|
31
|
+
_el$.$$keydown = (e) => {
|
|
32
|
+
if (e.isComposing) return;
|
|
33
|
+
if (e.key === "Enter") {
|
|
34
|
+
e.preventDefault();
|
|
35
|
+
e.stopPropagation();
|
|
36
|
+
handleCommit();
|
|
37
|
+
} else if (e.key === "Escape") {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
e.stopPropagation();
|
|
40
|
+
handleCancel();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
_el$.$$input = (e) => setDraft(e.currentTarget.value);
|
|
44
|
+
var _ref$ = inputRef;
|
|
45
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : inputRef = _el$;
|
|
46
|
+
effect(() => _el$.value = draft());
|
|
47
|
+
return _el$;
|
|
48
|
+
})();
|
|
49
|
+
return memo(() => ctx.value);
|
|
50
|
+
}
|
|
51
|
+
const gridsheetStyle = "sg-spreadsheet border-collapse [--sg-border:var(--color-zinc-300)] [--sg-bg:var(--color-white)] [--sg-fg:var(--color-zinc-950)] [--sg-header-bg:var(--color-zinc-100)] [--sg-header-fg:var(--color-zinc-600)] [--sg-header-selected-bg:var(--color-blue-100)] [--sg-selected-bg:var(--color-blue-50)] [--sg-active:var(--color-blue-500)] [--sg-cell-padding-x:0.5rem] [--sg-cell-padding-y:0.25rem] border border-(--sg-border) bg-(--sg-bg) text-(--sg-fg) [&_[data-slot=gridsheet-rowheader]]:border [&_[data-slot=gridsheet-rowheader]]:border-(--sg-border) [&_[data-slot=gridsheet-colheader]]:border [&_[data-slot=gridsheet-colheader]]:border-(--sg-border) [&_[data-slot=gridsheet-corner]]:border [&_[data-slot=gridsheet-corner]]:border-(--sg-border) [&_[data-slot=gridsheet-cell]]:border [&_[data-slot=gridsheet-cell]]:border-(--sg-border) [&_[data-slot=gridsheet-rowheader]]:bg-(--sg-header-bg) [&_[data-slot=gridsheet-colheader]]:bg-(--sg-header-bg) [&_[data-slot=gridsheet-corner]]:bg-(--sg-header-bg) [&_[data-slot=gridsheet-rowheader]]:font-semibold [&_[data-slot=gridsheet-colheader]]:font-semibold [&_[data-slot=gridsheet-rowheader]]:text-(--sg-header-fg) [&_[data-slot=gridsheet-colheader]]:text-(--sg-header-fg) [&_[data-slot=gridsheet-rowheader][data-selected]]:bg-(--sg-header-selected-bg) [&_[data-slot=gridsheet-colheader][data-selected]]:bg-(--sg-header-selected-bg) [&_[data-slot=gridsheet-rowheader]]:px-(--sg-cell-padding-x) [&_[data-slot=gridsheet-rowheader]]:py-(--sg-cell-padding-y) [&_[data-slot=gridsheet-colheader]]:px-(--sg-cell-padding-x) [&_[data-slot=gridsheet-colheader]]:py-(--sg-cell-padding-y) [&_[data-slot=gridsheet-cell]]:bg-(--sg-bg) [&_[data-slot=gridsheet-cell]]:px-(--sg-cell-padding-x) [&_[data-slot=gridsheet-cell]]:py-(--sg-cell-padding-y) [&_[data-slot=gridsheet-cell]]:min-w-20 [&_[data-slot=gridsheet-cell][data-selected]]:bg-(--sg-selected-bg) [&_[data-slot=gridsheet-cell][data-active]]:outline [&_[data-slot=gridsheet-cell][data-active]]:outline-2 [&_[data-slot=gridsheet-cell][data-active]]:outline-(--sg-active) [&_[data-slot=gridsheet-cell][data-active]]:-outline-offset-2 [&_[data-slot=gridsheet-cell][data-editing]]:bg-(--sg-bg) [&_[data-slot=gridsheet-preset-text-input]]:w-full [&_[data-slot=gridsheet-preset-text-input]]:h-full [&_[data-slot=gridsheet-preset-text-input]]:min-w-0 [&_[data-slot=gridsheet-preset-text-input]]:bg-transparent [&_[data-slot=gridsheet-preset-text-input]]:outline-none [&_[data-slot=gridsheet-preset-text-input]]:border-0 [&_[data-slot=gridsheet-preset-text-input]]:p-0 [&_[data-slot=gridsheet-preset-text-input]]:m-0 [&_[data-slot=gridsheet-preset-text-input]]:text-inherit [&_[data-slot=gridsheet-preset-text-input]]:font-inherit";
|
|
52
|
+
delegateEvents(["input", "keydown"]);
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { gridsheetStyle, textCellRenderer };
|
|
56
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","names":[],"sources":["../src/presets.tsx"],"sourcesContent":["import { createEffect, createSignal } from \"solid-js\";\nimport type { CellRenderContext } from \"./gridsheet\";\n\nexport function textCellRenderer(ctx: CellRenderContext<string>) {\n const [draft, setDraft] = createSignal(ctx.value);\n\n createEffect(() => {\n if (!ctx.isEditing) {\n setDraft(ctx.value);\n }\n });\n\n let inputRef: HTMLInputElement | undefined;\n createEffect(() => {\n if (!inputRef) return;\n if (ctx.isEditing) {\n inputRef.select();\n inputRef.focus();\n }\n });\n\n const handleCommit = () => {\n ctx.commitEdit(draft());\n queueMicrotask(() => ctx.cellRef?.focus());\n };\n const handleCancel = () => {\n setDraft(ctx.value);\n ctx.cancelEditing();\n queueMicrotask(() => ctx.cellRef?.focus());\n };\n\n if (ctx.isEditing) {\n return (\n <input\n data-slot=\"gridsheet-preset-text-input\"\n ref={inputRef}\n type=\"text\"\n value={draft()}\n onInput={(e) => setDraft(e.currentTarget.value)}\n onKeyDown={(e) => {\n if (e.isComposing) return;\n if (e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n handleCommit();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n handleCancel();\n }\n }}\n onBlur={handleCommit}\n />\n );\n }\n\n return <>{ctx.value}</>;\n}\n\nexport const gridsheetStyle =\n \"sg-spreadsheet border-collapse \" +\n \"[--sg-border:var(--color-zinc-300)] \" +\n \"[--sg-bg:var(--color-white)] \" +\n \"[--sg-fg:var(--color-zinc-950)] \" +\n \"[--sg-header-bg:var(--color-zinc-100)] \" +\n \"[--sg-header-fg:var(--color-zinc-600)] \" +\n \"[--sg-header-selected-bg:var(--color-blue-100)] \" +\n \"[--sg-selected-bg:var(--color-blue-50)] \" +\n \"[--sg-active:var(--color-blue-500)] \" +\n \"[--sg-cell-padding-x:0.5rem] \" +\n \"[--sg-cell-padding-y:0.25rem] \" +\n \"border \" +\n \"border-(--sg-border) \" +\n \"bg-(--sg-bg) \" +\n \"text-(--sg-fg) \" +\n \"[&_[data-slot=gridsheet-rowheader]]:border \" +\n \"[&_[data-slot=gridsheet-rowheader]]:border-(--sg-border) \" +\n \"[&_[data-slot=gridsheet-colheader]]:border \" +\n \"[&_[data-slot=gridsheet-colheader]]:border-(--sg-border) \" +\n \"[&_[data-slot=gridsheet-corner]]:border \" +\n \"[&_[data-slot=gridsheet-corner]]:border-(--sg-border) \" +\n \"[&_[data-slot=gridsheet-cell]]:border \" +\n \"[&_[data-slot=gridsheet-cell]]:border-(--sg-border) \" +\n \"[&_[data-slot=gridsheet-rowheader]]:bg-(--sg-header-bg) \" +\n \"[&_[data-slot=gridsheet-colheader]]:bg-(--sg-header-bg) \" +\n \"[&_[data-slot=gridsheet-corner]]:bg-(--sg-header-bg) \" +\n \"[&_[data-slot=gridsheet-rowheader]]:font-semibold \" +\n \"[&_[data-slot=gridsheet-colheader]]:font-semibold \" +\n \"[&_[data-slot=gridsheet-rowheader]]:text-(--sg-header-fg) \" +\n \"[&_[data-slot=gridsheet-colheader]]:text-(--sg-header-fg) \" +\n \"[&_[data-slot=gridsheet-rowheader][data-selected]]:bg-(--sg-header-selected-bg) \" +\n \"[&_[data-slot=gridsheet-colheader][data-selected]]:bg-(--sg-header-selected-bg) \" +\n \"[&_[data-slot=gridsheet-rowheader]]:px-(--sg-cell-padding-x) \" +\n \"[&_[data-slot=gridsheet-rowheader]]:py-(--sg-cell-padding-y) \" +\n \"[&_[data-slot=gridsheet-colheader]]:px-(--sg-cell-padding-x) \" +\n \"[&_[data-slot=gridsheet-colheader]]:py-(--sg-cell-padding-y) \" +\n \"[&_[data-slot=gridsheet-cell]]:bg-(--sg-bg) \" +\n \"[&_[data-slot=gridsheet-cell]]:px-(--sg-cell-padding-x) \" +\n \"[&_[data-slot=gridsheet-cell]]:py-(--sg-cell-padding-y) \" +\n \"[&_[data-slot=gridsheet-cell]]:min-w-20 \" +\n \"[&_[data-slot=gridsheet-cell][data-selected]]:bg-(--sg-selected-bg) \" +\n \"[&_[data-slot=gridsheet-cell][data-active]]:outline \" +\n \"[&_[data-slot=gridsheet-cell][data-active]]:outline-2 \" +\n \"[&_[data-slot=gridsheet-cell][data-active]]:outline-(--sg-active) \" +\n \"[&_[data-slot=gridsheet-cell][data-active]]:-outline-offset-2 \" +\n \"[&_[data-slot=gridsheet-cell][data-editing]]:bg-(--sg-bg) \" +\n // textCellRenderer preset\n \"[&_[data-slot=gridsheet-preset-text-input]]:w-full \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:h-full \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:min-w-0 \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:bg-transparent \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:outline-none \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:border-0 \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:p-0 \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:m-0 \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:text-inherit \" +\n \"[&_[data-slot=gridsheet-preset-text-input]]:font-inherit\";\n"],"mappings":";;;;;AAOA,SAAgB,iBAAQ,KAAA;CACtB,MAAM,CAAC,OAAO,YAAS,aAAA,IAAA,MAAA;AACvB,oBAAE;AACA,MAAA,CAAA,IAAA;GAGA;CACF,IAAI;AACJ,oBAAmB;AACjB,MAAI,CAAC,SAAU;AACf,MAAI,IAAI,WAAU;AAClB,YAAA,QAAA;AACA,YAAA,OAAA;;GAEA;CACF,MAAM,qBAAmB;AACvB,MAAI,WAAW,OAAO,CAAC;AACxB,uBAAA,IAAA,SAAA,OAAA,CAAA;;CAED,MAAM,qBAAe;AACnB,WAAS,IAAI,MAAM;AACnB,MAAI,eAAe;AACpB,uBAAA,IAAA,SAAA,OAAA,CAAA;;AAED,KAAI,IAAI,UACN,eAAO;EACL,IAAI,OAAC,QAAA;AACL,OAAK,iBAAiB,QAAQ,aAAU;AACxC,OAAK,aAAU,MAAA;AACb,OAAI,EAAE,YAAI;AACV,OAAI,EAAE,QAAQ,SAAA;AACZ,MAAE,gBAAgB;AAClB,MAAE,iBAAc;AAChB,kBAAc;cACL,EAAE,QAAQ,UAAI;AACvB,MAAE,gBAAgB;AAClB,MAAE,iBAAiB;AACnB,kBAAc;;;AAGlB,OAAK,WAAU,MAAK,SAAK,EAAA,cAAA,MAAA;EACzB,IAAI,QAAQ;AACZ,SAAI,UAAA,aAAA,IAAA,OAAA,KAAA,GAAA,WAAA;AACJ,eAAG,KAAA,QAAA,OAAA,CAAA;AACH,SAAO;KACN;AAEL,QAAA,WAAA,IAAA,MAAA;;AAEF,MAAa,iBAAY;AAGzB,eAAiB,CAAC,SAAS,UAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,36 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shiguri/solid-grid",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
3
5
|
"author": {
|
|
4
6
|
"name": "shiguri",
|
|
5
7
|
"url": "https://github.com/shiguri-01"
|
|
6
8
|
},
|
|
7
9
|
"repository": {
|
|
8
10
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/shiguri-01/solid-grid"
|
|
11
|
+
"url": "https://github.com/shiguri-01/solid-grid.git"
|
|
10
12
|
},
|
|
13
|
+
"homepage": "https://github.com/shiguri-01/solid-grid",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"solidjs"
|
|
16
|
+
],
|
|
11
17
|
"license": "MIT",
|
|
12
|
-
"version": "0.0.1",
|
|
13
18
|
"type": "module",
|
|
14
|
-
"
|
|
15
|
-
"module": "./dist/index.js",
|
|
16
|
-
"types": "./dist/index.d.ts",
|
|
19
|
+
"sideEffects": false,
|
|
17
20
|
"exports": {
|
|
18
21
|
".": {
|
|
19
22
|
"import": "./dist/index.js",
|
|
20
23
|
"types": "./dist/index.d.ts"
|
|
21
|
-
}
|
|
24
|
+
},
|
|
25
|
+
"./presets": {
|
|
26
|
+
"import": "./dist/presets.js",
|
|
27
|
+
"types": "./dist/presets.d.ts"
|
|
28
|
+
},
|
|
29
|
+
"./preset-tailwind.css": "./dist/preset-tailwind.css"
|
|
22
30
|
},
|
|
23
31
|
"files": [
|
|
24
|
-
"dist"
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
25
35
|
],
|
|
26
36
|
"scripts": {
|
|
27
|
-
"
|
|
37
|
+
"prepare": "lefthook install",
|
|
38
|
+
"lint": "biome lint --write",
|
|
39
|
+
"fmt": "biome format --write",
|
|
40
|
+
"build": "tsdown && node -e \"require('fs').copyFileSync('src/preset-tailwind.css', 'dist/preset-tailwind.css')\""
|
|
28
41
|
},
|
|
29
42
|
"peerDependencies": {
|
|
30
43
|
"solid-js": "^1.9.0"
|
|
31
44
|
},
|
|
32
45
|
"devDependencies": {
|
|
46
|
+
"@biomejs/biome": "2.3.4",
|
|
47
|
+
"@types/bun": "latest",
|
|
48
|
+
"lefthook": "^2.0.2",
|
|
33
49
|
"rolldown-plugin-solid": "^0.2.1",
|
|
34
|
-
"tsdown": "^0.16.1"
|
|
50
|
+
"tsdown": "^0.16.1",
|
|
51
|
+
"typescript": "^5.9.3"
|
|
35
52
|
}
|
|
36
53
|
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.tsx"],"sourcesContent":[],"mappings":";;;UAYiB,YAAA;;EAAA,GAAA,EAAA,MAAA;AAKjB;AA2BiB,UA3BA,SAAA,CA2BiB;EAQzB,GAAA,EAlCF,YAkCE;EAYE,GAAA,EA7CJ,YA6CI;;AAMY,UA1BN,iBA0BM,CAAA,CAAA,CAAA,CAAA;EAMN;EAET,GAAA,EAAA,MAAA;EACgB;EAGc,GAAA,EAAA,MAAA;EAAlB;EAAyB,KAAI,EA9BxC,CA8BwC;EAGlC;EACc,QAAA,EAAA,OAAA;EAGf;EACgB,UAAA,EAAA,OAAA;EAMtB;EAAyB,SAAA,EAAA,OAAA;EAEvB;EAEmC,OAAA,EApClC,oBAoCkC,GAAA,SAAA;EAAlB;EAAiB,SAAA,EAAA,GAAA,GAAA,IAAA;EAiB5B;EAAmC,UAAA,EAAA,CAAA,KAAA,EA/C7B,CA+C6B,EAAA,GAAA,IAAA;EAAf;EAAoB,aAAI,EAAA,GAAA,GAAA,IAAA;;UAzC3C;;QAET;wBACgB;;oBAGJ,kBAAkB,OAAO,GAAA,CAAI;;eAGlC;6BACc;;cAGf;8BACgB;;;;QAMtB,yBAAyB;;UAEvB,GAAA,CAAI;;2BAEa,kBAAkB;;;;;;;;;;;;;;;;;iBAiB7B,oBAAoB,eAAe,KAAK,GAAA,CAAI"}
|