From 55d1d57c654847d32d0db02de8c33c74e506e083 Mon Sep 17 00:00:00 2001 From: Nowely Date: Sat, 7 Mar 2026 16:25:42 +0300 Subject: [PATCH 1/8] refactor: replace TokenProvider with TokenContext for improved context management ## Summary - Refactored the context management by replacing `TokenProvider` with `TokenContext` across multiple components. - Updated imports and usage in `MarkedInput`, `MarkRenderer`, `TextSpan`, and `Token` components to utilize the new context. - Removed the deprecated `TokenProvider` and associated utility functions. ## Changes - Updated context provider usage in `MarkedInput.tsx`, `MarkRenderer.tsx`, `TextSpan.tsx`, and `Token.tsx`. - Introduced `TokenContext.ts` for the new context implementation. - Deleted `TokenProvider.ts` and `createContext.ts` as they are no longer needed. --- .../markput/src/components/MarkRenderer.tsx | 2 +- .../react/markput/src/components/MarkedInput.tsx | 4 ++-- .../react/markput/src/components/TextSpan.tsx | 2 +- packages/react/markput/src/components/Token.tsx | 10 +++++----- packages/react/markput/src/lib/hooks/useMark.tsx | 2 +- .../markput/src/lib/providers/TokenContext.ts | 13 +++++++++++++ .../markput/src/lib/providers/TokenProvider.ts | 5 ----- .../react/markput/src/lib/utils/createContext.ts | 16 ---------------- 8 files changed, 23 insertions(+), 31 deletions(-) create mode 100644 packages/react/markput/src/lib/providers/TokenContext.ts delete mode 100644 packages/react/markput/src/lib/providers/TokenProvider.ts delete mode 100644 packages/react/markput/src/lib/utils/createContext.ts diff --git a/packages/react/markput/src/components/MarkRenderer.tsx b/packages/react/markput/src/components/MarkRenderer.tsx index eff995c5..5714b889 100644 --- a/packages/react/markput/src/components/MarkRenderer.tsx +++ b/packages/react/markput/src/components/MarkRenderer.tsx @@ -2,7 +2,7 @@ import type {MarkToken} from '@markput/core' import {useSlot} from '../lib/hooks/useSlot' import {useStore} from '../lib/hooks/useStore' -import {useToken} from '../lib/providers/TokenProvider' +import {useToken} from '../lib/providers/TokenContext' import type {MarkProps} from '../types' // eslint-disable-next-line import/no-cycle import {Token} from './Token' diff --git a/packages/react/markput/src/components/MarkedInput.tsx b/packages/react/markput/src/components/MarkedInput.tsx index 60c526c7..a291b285 100644 --- a/packages/react/markput/src/components/MarkedInput.tsx +++ b/packages/react/markput/src/components/MarkedInput.tsx @@ -118,9 +118,9 @@ export function MarkedInput + - + ) } \ No newline at end of file diff --git a/packages/react/markput/src/components/TextSpan.tsx b/packages/react/markput/src/components/TextSpan.tsx index fa6705f0..6609d5d6 100644 --- a/packages/react/markput/src/components/TextSpan.tsx +++ b/packages/react/markput/src/components/TextSpan.tsx @@ -1,7 +1,7 @@ import {useLayoutEffect, useMemo, useRef} from 'react' import {useStore} from '../lib/hooks/useStore' -import {useToken} from '../lib/providers/TokenProvider' +import {useToken} from '../lib/providers/TokenContext' import {resolveSlot, resolveSlotProps} from '../lib/utils/resolveSlot' export const TextSpan = () => { diff --git a/packages/react/markput/src/components/Token.tsx b/packages/react/markput/src/components/Token.tsx index 19b8b364..8b376b62 100644 --- a/packages/react/markput/src/components/Token.tsx +++ b/packages/react/markput/src/components/Token.tsx @@ -1,7 +1,7 @@ import type {Token as TokenType} from '@markput/core' import {memo} from 'react' -import {TokenProvider} from '../lib/providers/TokenProvider' +import {TokenContext} from '../lib/providers/TokenContext' // eslint-disable-next-line import/no-cycle import {MarkRenderer} from './MarkRenderer' import {TextSpan} from './TextSpan' @@ -10,9 +10,9 @@ import {TextSpan} from './TextSpan' export const Token = memo(({mark, isNested = false}: {mark: TokenType; isNested?: boolean}) => { if (mark.type === 'mark') { return ( - + - + ) } @@ -21,9 +21,9 @@ export const Token = memo(({mark, isNested = false}: {mark: TokenType; isNested? } return ( - + - + ) }) diff --git a/packages/react/markput/src/lib/hooks/useMark.tsx b/packages/react/markput/src/lib/hooks/useMark.tsx index 44e963b7..ce7655b5 100644 --- a/packages/react/markput/src/lib/hooks/useMark.tsx +++ b/packages/react/markput/src/lib/hooks/useMark.tsx @@ -3,7 +3,7 @@ import {MarkHandler} from '@markput/core' import type {RefObject} from 'react' import {useEffect, useRef, useState} from 'react' -import {useToken} from '../providers/TokenProvider' +import {useToken} from '../providers/TokenContext' import {useStore} from './useStore' export interface MarkOptions { diff --git a/packages/react/markput/src/lib/providers/TokenContext.ts b/packages/react/markput/src/lib/providers/TokenContext.ts new file mode 100644 index 00000000..9666bba9 --- /dev/null +++ b/packages/react/markput/src/lib/providers/TokenContext.ts @@ -0,0 +1,13 @@ +import type {Token} from '@markput/core' +import {createContext, useContext} from 'react' + +export const TokenContext = createContext(undefined) +TokenContext.displayName = 'TokenProvider' + +export function useToken(): Token { + const value = useContext(TokenContext) + if (value === undefined) { + throw new Error('Token not found. Make sure to wrap component in TokenContext.Provider.') + } + return value +} \ No newline at end of file diff --git a/packages/react/markput/src/lib/providers/TokenProvider.ts b/packages/react/markput/src/lib/providers/TokenProvider.ts deleted file mode 100644 index da16ad8d..00000000 --- a/packages/react/markput/src/lib/providers/TokenProvider.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type {Token} from '@markput/core' - -import {createContext} from '../utils/createContext' - -export const [useToken, TokenProvider] = createContext('NodeProvider') \ No newline at end of file diff --git a/packages/react/markput/src/lib/utils/createContext.ts b/packages/react/markput/src/lib/utils/createContext.ts deleted file mode 100644 index f962f975..00000000 --- a/packages/react/markput/src/lib/utils/createContext.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {createContext as createReactContext, useContext} from 'react' - -export const createContext = (name: string) => { - const context = createReactContext(undefined) - context.displayName = name - - const useHook = () => { - const value = useContext(context) - if (value === undefined) { - throw new Error(`Context "${name}" not found. Make sure to wrap component in its Provider.`) - } - return value - } - - return [useHook, context.Provider, context] as const -} \ No newline at end of file From b47a3ad236e59b1f660a1fc79e116a31754f5451 Mon Sep 17 00:00:00 2001 From: Nowely Date: Sat, 7 Mar 2026 16:28:39 +0300 Subject: [PATCH 2/8] refactor: update useStore imports to use StoreContext provider ## Summary - Replaced imports of `useStore` from the deprecated `hooks` directory to the new `providers/StoreContext` across multiple components. - Removed the old `useStore` hook implementation as it is now integrated within the `StoreContext`. ## Changes - Updated imports in `BlockContainer`, `Container`, `MarkRenderer`, `OverlayRenderer`, `TextSpan`, `Suggestions`, `useMark`, `useOverlay`, and `useSlot` components. - Deleted the `useStore.ts` file from the `hooks` directory. - Enhanced `StoreContext.ts` to include a new `useStore` implementation with error handling. --- .../react/markput/src/components/BlockContainer.tsx | 2 +- packages/react/markput/src/components/Container.tsx | 2 +- .../react/markput/src/components/MarkRenderer.tsx | 2 +- .../react/markput/src/components/OverlayRenderer.tsx | 2 +- .../src/components/Suggestions/Suggestions.tsx | 2 +- packages/react/markput/src/components/TextSpan.tsx | 2 +- packages/react/markput/src/lib/hooks/useMark.tsx | 2 +- packages/react/markput/src/lib/hooks/useOverlay.tsx | 2 +- packages/react/markput/src/lib/hooks/useSlot.ts | 2 +- packages/react/markput/src/lib/hooks/useStore.ts | 11 ----------- .../react/markput/src/lib/providers/StoreContext.ts | 12 ++++++++++-- 11 files changed, 19 insertions(+), 22 deletions(-) delete mode 100644 packages/react/markput/src/lib/hooks/useStore.ts diff --git a/packages/react/markput/src/components/BlockContainer.tsx b/packages/react/markput/src/components/BlockContainer.tsx index 195995c3..0f5974fc 100644 --- a/packages/react/markput/src/components/BlockContainer.tsx +++ b/packages/react/markput/src/components/BlockContainer.tsx @@ -1,7 +1,7 @@ import {splitTokensIntoBlocks, reorderBlocks, parseWithParser, type Block} from '@markput/core' import {memo, useCallback, useMemo, useRef} from 'react' -import {useStore} from '../lib/hooks/useStore' +import {useStore} from '../lib/providers/StoreContext' import {resolveSlot, resolveSlotProps} from '../lib/utils/resolveSlot' import {DraggableBlock} from './DraggableBlock' import {Token} from './Token' diff --git a/packages/react/markput/src/components/Container.tsx b/packages/react/markput/src/components/Container.tsx index f73c38a7..de31f934 100644 --- a/packages/react/markput/src/components/Container.tsx +++ b/packages/react/markput/src/components/Container.tsx @@ -1,6 +1,6 @@ import {memo, useMemo} from 'react' -import {useStore} from '../lib/hooks/useStore' +import {useStore} from '../lib/providers/StoreContext' import {resolveSlot, resolveSlotProps} from '../lib/utils/resolveSlot' import {Token} from './Token' diff --git a/packages/react/markput/src/components/MarkRenderer.tsx b/packages/react/markput/src/components/MarkRenderer.tsx index 5714b889..ea2a9fa7 100644 --- a/packages/react/markput/src/components/MarkRenderer.tsx +++ b/packages/react/markput/src/components/MarkRenderer.tsx @@ -1,7 +1,7 @@ import type {MarkToken} from '@markput/core' import {useSlot} from '../lib/hooks/useSlot' -import {useStore} from '../lib/hooks/useStore' +import {useStore} from '../lib/providers/StoreContext' import {useToken} from '../lib/providers/TokenContext' import type {MarkProps} from '../types' // eslint-disable-next-line import/no-cycle diff --git a/packages/react/markput/src/components/OverlayRenderer.tsx b/packages/react/markput/src/components/OverlayRenderer.tsx index 05fa4ed7..f17d5d98 100644 --- a/packages/react/markput/src/components/OverlayRenderer.tsx +++ b/packages/react/markput/src/components/OverlayRenderer.tsx @@ -1,7 +1,7 @@ import {memo, useMemo} from 'react' import {useSlot} from '../lib/hooks/useSlot' -import {useStore} from '../lib/hooks/useStore' +import {useStore} from '../lib/providers/StoreContext' import {Suggestions} from './Suggestions' export const OverlayRenderer = memo(() => { diff --git a/packages/react/markput/src/components/Suggestions/Suggestions.tsx b/packages/react/markput/src/components/Suggestions/Suggestions.tsx index 2e63ea53..f7af8355 100644 --- a/packages/react/markput/src/components/Suggestions/Suggestions.tsx +++ b/packages/react/markput/src/components/Suggestions/Suggestions.tsx @@ -3,7 +3,7 @@ import type {RefObject} from 'react' import {useEffect, useMemo, useState} from 'react' import {useOverlay} from '../../lib/hooks/useOverlay' -import {useStore} from '../../lib/hooks/useStore' +import {useStore} from '../../lib/providers/StoreContext' import styles from '@markput/core/styles.module.css' diff --git a/packages/react/markput/src/components/TextSpan.tsx b/packages/react/markput/src/components/TextSpan.tsx index 6609d5d6..b163a5ed 100644 --- a/packages/react/markput/src/components/TextSpan.tsx +++ b/packages/react/markput/src/components/TextSpan.tsx @@ -1,6 +1,6 @@ import {useLayoutEffect, useMemo, useRef} from 'react' -import {useStore} from '../lib/hooks/useStore' +import {useStore} from '../lib/providers/StoreContext' import {useToken} from '../lib/providers/TokenContext' import {resolveSlot, resolveSlotProps} from '../lib/utils/resolveSlot' diff --git a/packages/react/markput/src/lib/hooks/useMark.tsx b/packages/react/markput/src/lib/hooks/useMark.tsx index ce7655b5..82a27425 100644 --- a/packages/react/markput/src/lib/hooks/useMark.tsx +++ b/packages/react/markput/src/lib/hooks/useMark.tsx @@ -3,8 +3,8 @@ import {MarkHandler} from '@markput/core' import type {RefObject} from 'react' import {useEffect, useRef, useState} from 'react' +import {useStore} from '../providers/StoreContext' import {useToken} from '../providers/TokenContext' -import {useStore} from './useStore' export interface MarkOptions { controlled?: boolean diff --git a/packages/react/markput/src/lib/hooks/useOverlay.tsx b/packages/react/markput/src/lib/hooks/useOverlay.tsx index 0b735ac4..5eca0bb7 100644 --- a/packages/react/markput/src/lib/hooks/useOverlay.tsx +++ b/packages/react/markput/src/lib/hooks/useOverlay.tsx @@ -4,7 +4,7 @@ import type {RefObject} from 'react' import {useCallback, useMemo} from 'react' import type {Option} from '../../types' -import {useStore} from './useStore' +import {useStore} from '../providers/StoreContext' export interface OverlayHandler { style: { diff --git a/packages/react/markput/src/lib/hooks/useSlot.ts b/packages/react/markput/src/lib/hooks/useSlot.ts index ea48f585..2b7d3829 100644 --- a/packages/react/markput/src/lib/hooks/useSlot.ts +++ b/packages/react/markput/src/lib/hooks/useSlot.ts @@ -1,7 +1,7 @@ import type {ComponentType} from 'react' import type {MarkProps, Option, OverlayProps} from '../../types' -import {useStore} from './useStore' +import {useStore} from '../providers/StoreContext' export type SlotType = 'mark' | 'overlay' diff --git a/packages/react/markput/src/lib/hooks/useStore.ts b/packages/react/markput/src/lib/hooks/useStore.ts deleted file mode 100644 index 72d361e3..00000000 --- a/packages/react/markput/src/lib/hooks/useStore.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type {Store} from '@markput/core' -import {assertNonNullable} from '@markput/core' -import {useContext} from 'react' - -import {StoreContext} from '../providers/StoreContext' - -export function useStore(): Store { - const store = useContext(StoreContext) - assertNonNullable(store) - return store -} \ No newline at end of file diff --git a/packages/react/markput/src/lib/providers/StoreContext.ts b/packages/react/markput/src/lib/providers/StoreContext.ts index 0cc51ed2..573fd434 100644 --- a/packages/react/markput/src/lib/providers/StoreContext.ts +++ b/packages/react/markput/src/lib/providers/StoreContext.ts @@ -1,5 +1,13 @@ import type {Store} from '@markput/core' -import {createContext} from 'react' +import {createContext, useContext} from 'react' export const StoreContext = createContext(undefined) -StoreContext.displayName = 'StoreContext' \ No newline at end of file +StoreContext.displayName = 'StoreContext' + +export function useStore(): Store { + const store = useContext(StoreContext) + if (store === undefined) { + throw new Error('Store not found. Make sure to wrap component in StoreContext.') + } + return store +} \ No newline at end of file From abbe430c842a765fc2c6f46bc7a7e4e3fcac0f3f Mon Sep 17 00:00:00 2001 From: Nowely Date: Sat, 7 Mar 2026 16:45:38 +0300 Subject: [PATCH 3/8] feat: introduce slot resolution utilities for React and Vue ## Summary - Added new utility functions `resolveSlot` and `resolveSlotProps` to handle slot resolution in both React and Vue components. - Updated existing components to utilize the new slot utilities, improving code organization and maintainability. - Removed the old slot resolution implementation from the `utils` directory. ## Changes - Created `slots.ts` in both React and Vue libraries to encapsulate slot resolution logic. - Updated imports in `BlockContainer`, `Container`, and `TextSpan` components to use the new slot utilities. - Enhanced type definitions for better TypeScript support. --- packages/common/core/index.ts | 2 +- .../common/core/src/shared/utils/index.ts | 3 ++- .../core/src/shared}/utils/resolveSlot.ts | 17 +++++------- .../markput/src/components/BlockContainer.tsx | 2 +- .../markput/src/components/Container.tsx | 2 +- .../react/markput/src/components/TextSpan.tsx | 2 +- packages/react/markput/src/lib/slots.ts | 14 ++++++++++ .../markput/src/lib/utils/resolveSlot.ts | 26 ------------------- .../markput/src/components/BlockContainer.vue | 4 +-- .../vue/markput/src/components/Container.vue | 4 +-- .../vue/markput/src/components/TextSpan.vue | 3 +-- packages/vue/markput/src/lib/slots.ts | 14 ++++++++++ 12 files changed, 45 insertions(+), 48 deletions(-) rename packages/{vue/markput/src/lib => common/core/src/shared}/utils/resolveSlot.ts (51%) create mode 100644 packages/react/markput/src/lib/slots.ts delete mode 100644 packages/react/markput/src/lib/utils/resolveSlot.ts create mode 100644 packages/vue/markput/src/lib/slots.ts diff --git a/packages/common/core/index.ts b/packages/common/core/index.ts index 234ff880..559e25ca 100644 --- a/packages/common/core/index.ts +++ b/packages/common/core/index.ts @@ -1,6 +1,6 @@ // Shared exports export {assertNonNullable} from './src/shared/checkers/assertNonNullable' -export {convertDataAttrs, cx, merge} from './src/shared/utils' +export {convertDataAttrs, cx, merge, resolveSlot, resolveSlotProps, type SlotName} from './src/shared/utils' export {KEYBOARD, DEFAULT_MARKUP, DEFAULT_OVERLAY_TRIGGER} from './src/shared/constants' export type { OverlayMatch, diff --git a/packages/common/core/src/shared/utils/index.ts b/packages/common/core/src/shared/utils/index.ts index 82c0c37b..3bbc5117 100644 --- a/packages/common/core/src/shared/utils/index.ts +++ b/packages/common/core/src/shared/utils/index.ts @@ -1,3 +1,4 @@ export {convertDataAttrs} from './dataAttributes' export {cx} from './cx' -export {merge} from './merge' \ No newline at end of file +export {merge} from './merge' +export {resolveSlot, resolveSlotProps, type SlotName} from './resolveSlot' \ No newline at end of file diff --git a/packages/vue/markput/src/lib/utils/resolveSlot.ts b/packages/common/core/src/shared/utils/resolveSlot.ts similarity index 51% rename from packages/vue/markput/src/lib/utils/resolveSlot.ts rename to packages/common/core/src/shared/utils/resolveSlot.ts index 86e3af2c..47ca92ce 100644 --- a/packages/vue/markput/src/lib/utils/resolveSlot.ts +++ b/packages/common/core/src/shared/utils/resolveSlot.ts @@ -1,6 +1,5 @@ -import type {CoreSlotProps, CoreSlots} from '@markput/core' -import {convertDataAttrs} from '@markput/core' -import type {Component} from 'vue' +import type {CoreSlotProps, CoreSlots, GenericAttributes, GenericElement} from '../types' +import {convertDataAttrs} from './dataAttributes' export type SlotName = 'container' | 'span' @@ -9,18 +8,14 @@ const defaultSlots: Record = { span: 'span', } -export function resolveSlot(slotName: SlotName, slots: CoreSlots | undefined): string | Component { - if (slots?.[slotName]) { - return slots[slotName] as string | Component - } - - return defaultSlots[slotName] +export function resolveSlot(slotName: SlotName, slots: CoreSlots | undefined): GenericElement { + return slots?.[slotName] ?? defaultSlots[slotName] } export function resolveSlotProps( slotName: SlotName, slotProps: CoreSlotProps | undefined -): Record | undefined { +): GenericAttributes | undefined { const props = slotProps?.[slotName] - return props ? (convertDataAttrs(props as Record) as Record) : undefined + return props ? (convertDataAttrs(props as Record) as GenericAttributes) : undefined } \ No newline at end of file diff --git a/packages/react/markput/src/components/BlockContainer.tsx b/packages/react/markput/src/components/BlockContainer.tsx index 0f5974fc..52740cef 100644 --- a/packages/react/markput/src/components/BlockContainer.tsx +++ b/packages/react/markput/src/components/BlockContainer.tsx @@ -2,7 +2,7 @@ import {splitTokensIntoBlocks, reorderBlocks, parseWithParser, type Block} from import {memo, useCallback, useMemo, useRef} from 'react' import {useStore} from '../lib/providers/StoreContext' -import {resolveSlot, resolveSlotProps} from '../lib/utils/resolveSlot' +import {resolveSlot, resolveSlotProps} from '../lib/slots' import {DraggableBlock} from './DraggableBlock' import {Token} from './Token' diff --git a/packages/react/markput/src/components/Container.tsx b/packages/react/markput/src/components/Container.tsx index de31f934..e58f0e0c 100644 --- a/packages/react/markput/src/components/Container.tsx +++ b/packages/react/markput/src/components/Container.tsx @@ -1,7 +1,7 @@ import {memo, useMemo} from 'react' import {useStore} from '../lib/providers/StoreContext' -import {resolveSlot, resolveSlotProps} from '../lib/utils/resolveSlot' +import {resolveSlot, resolveSlotProps} from '../lib/slots' import {Token} from './Token' export const Container = memo(() => { diff --git a/packages/react/markput/src/components/TextSpan.tsx b/packages/react/markput/src/components/TextSpan.tsx index b163a5ed..2bbe3dc9 100644 --- a/packages/react/markput/src/components/TextSpan.tsx +++ b/packages/react/markput/src/components/TextSpan.tsx @@ -2,7 +2,7 @@ import {useLayoutEffect, useMemo, useRef} from 'react' import {useStore} from '../lib/providers/StoreContext' import {useToken} from '../lib/providers/TokenContext' -import {resolveSlot, resolveSlotProps} from '../lib/utils/resolveSlot' +import {resolveSlot, resolveSlotProps} from '../lib/slots' export const TextSpan = () => { const token = useToken() diff --git a/packages/react/markput/src/lib/slots.ts b/packages/react/markput/src/lib/slots.ts new file mode 100644 index 00000000..d0081f65 --- /dev/null +++ b/packages/react/markput/src/lib/slots.ts @@ -0,0 +1,14 @@ +import type {SlotName} from '@markput/core' +import {resolveSlot as resolveSlotCore, resolveSlotProps as resolveSlotPropsCore} from '@markput/core' +import type {ElementType, HTMLAttributes} from 'react' + +export function resolveSlot(slotName: SlotName, slots: Parameters[1]): ElementType { + return resolveSlotCore(slotName, slots) as ElementType +} + +export function resolveSlotProps( + slotName: SlotName, + slotProps: Parameters[1] +): HTMLAttributes | undefined { + return resolveSlotPropsCore(slotName, slotProps) as HTMLAttributes | undefined +} \ No newline at end of file diff --git a/packages/react/markput/src/lib/utils/resolveSlot.ts b/packages/react/markput/src/lib/utils/resolveSlot.ts deleted file mode 100644 index d14fba42..00000000 --- a/packages/react/markput/src/lib/utils/resolveSlot.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type {CoreSlotProps, CoreSlots} from '@markput/core' -import {convertDataAttrs} from '@markput/core' -import type {ElementType, HTMLAttributes} from 'react' - -export type SlotName = 'container' | 'span' - -const defaultSlots: Record = { - container: 'div', - span: 'span', -} - -export function resolveSlot(slotName: SlotName, slots: CoreSlots | undefined): ElementType { - if (slots?.[slotName]) { - return slots[slotName] as ElementType - } - - return defaultSlots[slotName] -} - -export function resolveSlotProps( - slotName: SlotName, - slotProps: CoreSlotProps | undefined -): HTMLAttributes | undefined { - const props = slotProps?.[slotName] - return props ? (convertDataAttrs(props as Record) as HTMLAttributes) : undefined -} \ No newline at end of file diff --git a/packages/vue/markput/src/components/BlockContainer.vue b/packages/vue/markput/src/components/BlockContainer.vue index 22742133..74592f43 100644 --- a/packages/vue/markput/src/components/BlockContainer.vue +++ b/packages/vue/markput/src/components/BlockContainer.vue @@ -1,10 +1,10 @@ diff --git a/packages/vue/markput/src/components/OverlayRenderer.vue b/packages/vue/markput/src/components/OverlayRenderer.vue index b5a43579..e23360ea 100644 --- a/packages/vue/markput/src/components/OverlayRenderer.vue +++ b/packages/vue/markput/src/components/OverlayRenderer.vue @@ -1,29 +1,24 @@ From 62b5383eca1a1a85d4ffe2308d86920d21d76711 Mon Sep 17 00:00:00 2001 From: Nowely Date: Sat, 7 Mar 2026 17:20:36 +0300 Subject: [PATCH 6/8] refactor: move DEFAULT_OPTIONS and createMarkFromOverlay to core - Move DEFAULT_OPTIONS constant from React/Vue to @markput/core - Create createMarkFromOverlay utility for token creation from overlay matches - Remove duplicated constants.ts files from both framework packages - Update useOverlay hooks to use new core utility --- packages/common/core/index.ts | 11 +++++-- .../features/overlay/createMarkFromOverlay.ts | 26 ++++++++++++++++ .../common/core/src/features/overlay/index.ts | 3 +- packages/common/core/src/shared/constants.ts | 22 +++++++++++++- .../markput/src/components/MarkedInput.tsx | 3 +- packages/react/markput/src/constants.ts | 24 --------------- .../markput/src/lib/hooks/useOverlay.tsx | 18 ++--------- .../markput/src/components/MarkedInput.vue | 3 +- packages/vue/markput/src/constants.ts | 13 -------- .../vue/markput/src/lib/hooks/useOverlay.ts | 18 ++--------- .../content/docs/api/functions/MarkedInput.md | 2 +- .../docs/api/interfaces/MarkedInputProps.md | 30 +++++++++---------- 12 files changed, 82 insertions(+), 91 deletions(-) create mode 100644 packages/common/core/src/features/overlay/createMarkFromOverlay.ts delete mode 100644 packages/react/markput/src/constants.ts delete mode 100644 packages/vue/markput/src/constants.ts diff --git a/packages/common/core/index.ts b/packages/common/core/index.ts index 559e25ca..617101c4 100644 --- a/packages/common/core/index.ts +++ b/packages/common/core/index.ts @@ -1,7 +1,14 @@ // Shared exports export {assertNonNullable} from './src/shared/checkers/assertNonNullable' export {convertDataAttrs, cx, merge, resolveSlot, resolveSlotProps, type SlotName} from './src/shared/utils' -export {KEYBOARD, DEFAULT_MARKUP, DEFAULT_OVERLAY_TRIGGER} from './src/shared/constants' +export { + KEYBOARD, + DEFAULT_MARKUP, + DEFAULT_OVERLAY_TRIGGER, + DEFAULT_OPTIONS, + type DefaultOption, + type DefaultOverlayConfig, +} from './src/shared/constants' export type { OverlayMatch, EventKey, @@ -43,7 +50,7 @@ export {findGap, getClosestIndexes} from './src/features/preparsing' export {toString} from './src/features/parsing' export {shallow, createNewSpan, deleteMark} from './src/features/text-manipulation' export {Store, type StoreOptions} from './src/features/store' -export {OverlayController} from './src/features/overlay' +export {OverlayController, createMarkFromOverlay} from './src/features/overlay' export {FocusController} from './src/features/focus' export {KeyDownController} from './src/features/input' export {SystemListenerController} from './src/features/events' diff --git a/packages/common/core/src/features/overlay/createMarkFromOverlay.ts b/packages/common/core/src/features/overlay/createMarkFromOverlay.ts new file mode 100644 index 00000000..eaebc043 --- /dev/null +++ b/packages/common/core/src/features/overlay/createMarkFromOverlay.ts @@ -0,0 +1,26 @@ +import type {OverlayMatch} from '../../shared/types' +import type {MarkToken} from '../parsing' + +export function createMarkFromOverlay(match: OverlayMatch, value: string, meta?: string): MarkToken { + return { + type: 'mark', + value, + meta, + content: '', + position: { + start: match.index, + end: match.index + match.span.length, + }, + descriptor: { + markup: match.option.markup!, + index: 0, + segments: [], + gapTypes: [], + hasNested: false, + hasTwoValues: false, + segmentGlobalIndices: [], + }, + children: [], + nested: undefined, + } +} \ No newline at end of file diff --git a/packages/common/core/src/features/overlay/index.ts b/packages/common/core/src/features/overlay/index.ts index 61edbdf6..c50ac646 100644 --- a/packages/common/core/src/features/overlay/index.ts +++ b/packages/common/core/src/features/overlay/index.ts @@ -1 +1,2 @@ -export {OverlayController} from './OverlayController' \ No newline at end of file +export {OverlayController} from './OverlayController' +export {createMarkFromOverlay} from './createMarkFromOverlay' \ No newline at end of file diff --git a/packages/common/core/src/shared/constants.ts b/packages/common/core/src/shared/constants.ts index 780f4ab5..0a36d9a2 100644 --- a/packages/common/core/src/shared/constants.ts +++ b/packages/common/core/src/shared/constants.ts @@ -1,4 +1,14 @@ import type {Markup} from '../features/parsing/ParserV2/types' +import type {CoreOption} from './types' + +export interface DefaultOverlayConfig { + trigger?: string + data?: string[] +} + +export interface DefaultOption extends CoreOption { + overlay?: DefaultOverlayConfig +} export enum KEYBOARD { // Navigation Keys @@ -27,4 +37,14 @@ export enum KEYBOARD { export const DEFAULT_OVERLAY_TRIGGER = '@' -export const DEFAULT_MARKUP: Markup = '@[__value__](__meta__)' \ No newline at end of file +export const DEFAULT_MARKUP: Markup = '@[__value__](__meta__)' + +export const DEFAULT_OPTIONS: DefaultOption[] = [ + { + markup: DEFAULT_MARKUP, + overlay: { + trigger: DEFAULT_OVERLAY_TRIGGER, + data: [], + }, + }, +] \ No newline at end of file diff --git a/packages/react/markput/src/components/MarkedInput.tsx b/packages/react/markput/src/components/MarkedInput.tsx index a291b285..56630581 100644 --- a/packages/react/markput/src/components/MarkedInput.tsx +++ b/packages/react/markput/src/components/MarkedInput.tsx @@ -1,9 +1,8 @@ import type {CoreSlotProps, CoreSlots, MarkputHandler, OverlayTrigger, StyleProperties} from '@markput/core' -import {cx, merge, Store} from '@markput/core' +import {cx, DEFAULT_OPTIONS, merge, Store} from '@markput/core' import type {ComponentType, CSSProperties, Ref} from 'react' import {useState} from 'react' -import {DEFAULT_OPTIONS} from '../constants' import {createUseHook} from '../lib/hooks/createUseHook' import {useCoreFeatures} from '../lib/hooks/useCoreFeatures' import {StoreContext} from '../lib/providers/StoreContext' diff --git a/packages/react/markput/src/constants.ts b/packages/react/markput/src/constants.ts deleted file mode 100644 index 7ee76d14..00000000 --- a/packages/react/markput/src/constants.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {DEFAULT_MARKUP, DEFAULT_OVERLAY_TRIGGER} from '@markput/core' - -import type {Option} from './types' - -/** - * React-specific default options for MarkedInput. - * Extends core DEFAULT_OPTIONS with framework-specific configuration: - * - Includes trigger configuration via overlay.trigger - * - Provides empty data array for overlay suggestions - * - * Architecture: - * - Core maintains framework-agnostic DEFAULT_OPTIONS (markup only) - * - React layer extends with trigger and overlay configuration - * - This keeps separation of concerns: core focuses on parsing, React on UI - */ -export const DEFAULT_OPTIONS: Option[] = [ - { - markup: DEFAULT_MARKUP, - overlay: { - trigger: DEFAULT_OVERLAY_TRIGGER, - data: [], - }, - }, -] \ No newline at end of file diff --git a/packages/react/markput/src/lib/hooks/useOverlay.tsx b/packages/react/markput/src/lib/hooks/useOverlay.tsx index 5eca0bb7..0db2ddd4 100644 --- a/packages/react/markput/src/lib/hooks/useOverlay.tsx +++ b/packages/react/markput/src/lib/hooks/useOverlay.tsx @@ -1,5 +1,5 @@ -import type {OverlayMatch, Token} from '@markput/core' -import {Caret} from '@markput/core' +import type {OverlayMatch} from '@markput/core' +import {Caret, createMarkFromOverlay} from '@markput/core' import type {RefObject} from 'react' import {useCallback, useMemo} from 'react' @@ -25,19 +25,7 @@ export function useOverlay(): OverlayHandler { const close = useCallback(() => store.events.clearOverlay(), []) const select = useCallback( (value: {value: string; meta?: string}) => { - const mark: Token = { - type: 'mark', - value: value.value, - meta: value.meta, - content: '', - position: {start: match.index, end: match.index + match.span.length}, - descriptor: { - index: 0, - markup: match.option.markup, - } as any, - children: [], - nested: undefined, - } + const mark = createMarkFromOverlay(match, value.value, value.meta) store.events.select({mark, match}) store.events.clearOverlay() }, diff --git a/packages/vue/markput/src/components/MarkedInput.vue b/packages/vue/markput/src/components/MarkedInput.vue index a103d124..025d8882 100644 --- a/packages/vue/markput/src/components/MarkedInput.vue +++ b/packages/vue/markput/src/components/MarkedInput.vue @@ -1,9 +1,8 @@