text-slicer 2.0.1 → 2.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/README.md +174 -40
- package/dist/index.cjs +200 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -4
- package/dist/index.d.ts +17 -4
- package/dist/index.js +200 -82
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["export type SplitMode = 'words' | 'chars' | 'both';\n\nexport interface TextSlicerOptions {\n container?: HTMLElement | string;\n splitMode?: SplitMode;\n cssVariables?: boolean;\n dataAttributes?: boolean;\n keepWhitespaceNodes?: boolean;\n containerHeightVar?: boolean;\n}\n\nexport interface TextSlicerMetrics {\n wordTotal: number;\n charTotal: number;\n renderedAt: number;\n}\n\nexport interface TextSlicerCallbacks {\n onAfterRender?: (metrics: TextSlicerMetrics) => void;\n}\n\ntype RuntimeOptions = Required<Omit<TextSlicerOptions, 'container'>>;\n\nconst DEFAULT_OPTIONS: RuntimeOptions = {\n splitMode: 'both',\n cssVariables: false,\n dataAttributes: false,\n keepWhitespaceNodes: true,\n containerHeightVar: false,\n};\n\nexport const CLASSNAMES = Object.freeze({\n word: 'ts-word',\n char: 'ts-char',\n whitespace: 'ts-whitespace',\n});\n\nconst SPACE = ' ';\nconst CSS_VAR_WORD_TOTAL = '--word-total';\nconst CSS_VAR_CHAR_TOTAL = '--char-total';\nconst CSS_VAR_WORD_INDEX = '--word-index';\nconst CSS_VAR_CHAR_INDEX = '--char-index';\nconst CSS_VAR_CONTAINER_HEIGHT = '--container-height';\nconst MEASURING_CLASS = 'ts-measuring';\n\nconst canUseDOM = (): boolean => typeof window !== 'undefined' && typeof document !== 'undefined';\n\nconst resolveContainer = (container?: HTMLElement | string): HTMLElement | null => {\n if (!canUseDOM()) return null;\n if (!container) return null;\n\n return typeof container === 'string' ? document.querySelector(container) : container;\n};\n\ntype IntlWithSegmenter = typeof Intl & {\n Segmenter?: new (locales?: string | string[], options?: Intl.SegmenterOptions) => Intl.Segmenter;\n};\n\nconst splitIntoGraphemes = (text: string): string[] => {\n const Seg = (Intl as IntlWithSegmenter).Segmenter;\n\n if (typeof Seg === 'function') {\n const segmenter = new Seg('en', { granularity: 'grapheme' });\n return Array.from(segmenter.segment(text), (s: Intl.SegmentData) => s.segment);\n }\n\n return Array.from(text);\n};\n\nconst splitIntoWords = (text: string): string[] => text.split(SPACE);\n\nconst emptyElement = (el: HTMLElement): void => {\n el.replaceChildren();\n};\n\nconst isHTMLElement = (el: unknown): el is HTMLElement =>\n !!el && typeof HTMLElement !== 'undefined' && el instanceof HTMLElement;\n\ntype NonUndefined<T> = T extends undefined ? never : T;\ntype OmitUndefined<T extends Record<string, unknown>> = {\n [K in keyof T as T[K] extends undefined ? never : K]: NonUndefined<T[K]>;\n};\n\nconst omitUndefined = <T extends Record<string, unknown>>(obj: T): OmitUndefined<T> => {\n const out = {} as OmitUndefined<T>;\n\n (Object.keys(obj) as Array<keyof T>).forEach((key) => {\n const val = obj[key];\n\n if (val !== undefined) {\n (out as Record<string, unknown>)[key as string] = val as unknown;\n }\n });\n\n return out;\n};\n\nexport class TextSlicer {\n private readonly el: HTMLElement | null;\n private original: string;\n private opts: RuntimeOptions;\n private callbacks: TextSlicerCallbacks | undefined;\n private charIndex: number;\n private mounted: boolean;\n private resizeObserver?: ResizeObserver;\n\n constructor(options: TextSlicerOptions = {}, callbacks?: TextSlicerCallbacks) {\n const el = resolveContainer(options.container);\n this.el = el;\n this.original = isHTMLElement(el) ? (el.textContent?.toString() ?? '') : '';\n this.opts = {\n ...DEFAULT_OPTIONS,\n ...omitUndefined<Omit<TextSlicerOptions, 'container'>>(options),\n } as RuntimeOptions;\n\n this.callbacks = callbacks;\n this.charIndex = 0;\n this.mounted = false;\n }\n\n get metrics(): TextSlicerMetrics {\n const text = this.original;\n\n return {\n wordTotal: text.length ? splitIntoWords(text).length : 0,\n charTotal: text.length,\n renderedAt: Date.now(),\n };\n }\n\n init(): void {\n if (!this.el) return;\n\n this.mounted = true;\n this.split();\n\n if (this.opts.containerHeightVar) {\n this.initHeightObserver();\n }\n }\n\n reinit(newText?: string, next?: Partial<TextSlicerOptions>): void {\n if (!this.el) return;\n if (typeof newText === 'string') this.original = newText;\n if (next) this.opts = { ...this.opts, ...omitUndefined(next) } as RuntimeOptions;\n\n this.split();\n }\n\n clear(): void {\n if (!this.el) return;\n\n emptyElement(this.el);\n }\n\n split(): void {\n if (!this.el) return;\n\n this.clear();\n this.charIndex = 0;\n\n const text = this.original;\n const fragment = document.createDocumentFragment();\n const words = splitIntoWords(text);\n\n if (this.opts.splitMode === 'chars') {\n this.appendChars(fragment, text);\n } else {\n this.appendWords(fragment, words);\n }\n\n this.el.appendChild(fragment);\n\n if (this.opts.cssVariables) {\n this.el.style.setProperty(CSS_VAR_WORD_TOTAL, String(words.length));\n this.el.style.setProperty(CSS_VAR_CHAR_TOTAL, String(text.length));\n }\n\n this.callbacks?.onAfterRender?.(this.metrics);\n }\n\n destroy(): void {\n if (!this.el) return;\n\n this.clear();\n this.unlockHeight();\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = undefined;\n }\n\n if (this.opts.containerHeightVar) {\n this.el.style.removeProperty(CSS_VAR_CONTAINER_HEIGHT);\n }\n\n this.mounted = false;\n }\n\n updateOptions(next: Partial<TextSlicerOptions>): void {\n this.opts = { ...this.opts, ...omitUndefined(next) } as RuntimeOptions;\n\n if (this.mounted) this.split();\n }\n\n lockHeight(): void {\n if (!this.el) return;\n\n const h = this.measureHeight();\n\n if (h > 0) {\n this.el.style.height = `${h}px`;\n }\n }\n\n unlockHeight(): void {\n if (!this.el) return;\n\n this.el.style.removeProperty('height');\n }\n\n private appendWords(fragment: DocumentFragment, words: string[]): void {\n words.forEach((word, wordIndex) => {\n if (this.opts.splitMode === 'both') {\n const wordSpan = this.createWordSpan(wordIndex, word);\n\n for (const ch of splitIntoGraphemes(word)) {\n const charSpan = this.createCharSpan(ch);\n\n wordSpan.append(charSpan);\n }\n\n fragment.append(wordSpan);\n } else {\n const wordSpan = this.createWordSpan(wordIndex);\n\n wordSpan.append(document.createTextNode(word));\n fragment.append(wordSpan);\n }\n\n if (wordIndex < words.length - 1) {\n fragment.append(this.createSpaceSpan());\n }\n });\n }\n\n private appendChars(fragment: DocumentFragment, text: string): void {\n for (const ch of splitIntoGraphemes(text)) {\n const span = this.createCharSpan(ch);\n\n fragment.append(span);\n }\n }\n\n private createWordSpan(index: number, word: string = ''): HTMLSpanElement {\n const span = document.createElement('span');\n\n span.classList.add(CLASSNAMES.word);\n\n if (this.opts.dataAttributes && word) {\n span.setAttribute('data-word', word);\n }\n\n if (this.opts.cssVariables) {\n span.style.setProperty(CSS_VAR_WORD_INDEX, String(index));\n }\n\n return span;\n }\n\n private createCharSpan(ch: string): HTMLSpanElement {\n const span = document.createElement('span');\n\n span.textContent = ch;\n\n if (this.opts.dataAttributes) span.setAttribute('data-char', ch);\n\n if (ch === SPACE) {\n span.classList.add(CLASSNAMES.whitespace);\n\n if (!this.opts.keepWhitespaceNodes) span.textContent = SPACE;\n } else {\n span.classList.add(CLASSNAMES.char);\n\n if (this.opts.cssVariables) {\n span.style.setProperty(CSS_VAR_CHAR_INDEX, String(this.charIndex));\n }\n\n this.charIndex += 1;\n }\n\n return span;\n }\n\n private createSpaceSpan(): HTMLSpanElement {\n const span = document.createElement('span');\n\n span.classList.add(CLASSNAMES.whitespace);\n span.textContent = SPACE;\n\n return span;\n }\n\n private measureHeight(): number {\n if (!this.el) return 0;\n\n this.el.classList.add(MEASURING_CLASS);\n void this.el.offsetHeight;\n\n let h = this.el.offsetHeight || this.el.clientHeight || 0;\n\n if (!h) {\n h = Math.round(this.el.getBoundingClientRect().height);\n }\n\n this.el.classList.remove(MEASURING_CLASS);\n\n return Math.max(0, Math.ceil(h));\n }\n\n private initHeightObserver(): void {\n if (!this.el) return;\n\n this.resizeObserver = new ResizeObserver(() => {\n const h = this.measureHeight();\n\n if (h > 0) {\n this.el?.style.setProperty(CSS_VAR_CONTAINER_HEIGHT, `${h}px`);\n }\n });\n\n this.resizeObserver.observe(this.el);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["export type SplitMode = 'words' | 'chars' | 'both';\n\nexport interface TextSlicerOptions {\n container?: HTMLElement | string;\n splitMode?: SplitMode;\n cssVariables?: boolean;\n dataAttributes?: boolean;\n keepWhitespaceNodes?: boolean;\n containerHeightVar?: boolean;\n locale?: string | string[];\n}\n\nexport interface TextSlicerMetrics {\n wordTotal: number;\n charTotal: number;\n renderedAt: number;\n}\n\nexport interface TextSlicerCallbacks {\n onAfterRender?: (metrics: TextSlicerMetrics) => void;\n}\n\ntype RuntimeOptions = Required<Omit<TextSlicerOptions, 'container' | 'locale'>> &\n Pick<TextSlicerOptions, 'locale'>;\n\nconst DEFAULT_OPTIONS: RuntimeOptions = {\n splitMode: 'both',\n cssVariables: false,\n dataAttributes: false,\n keepWhitespaceNodes: true,\n containerHeightVar: false,\n locale: undefined,\n};\n\nexport const CLASSNAMES = Object.freeze({\n word: 'ts-word',\n char: 'ts-char',\n whitespace: 'ts-whitespace',\n});\n\nconst CSS_VAR_WORD_TOTAL = '--word-total';\nconst CSS_VAR_CHAR_TOTAL = '--char-total';\nconst CSS_VAR_WORD_INDEX = '--word-index';\nconst CSS_VAR_CHAR_INDEX = '--char-index';\nconst CSS_VAR_CONTAINER_HEIGHT = '--container-height';\nconst MEASURING_CLASS = 'ts-measuring';\n\nconst canUseDOM = (): boolean => typeof window !== 'undefined' && typeof document !== 'undefined';\n\nconst resolveContainer = (container?: HTMLElement | string): HTMLElement | null => {\n if (!canUseDOM()) return null;\n if (!container) return null;\n\n return typeof container === 'string' ? document.querySelector(container) : container;\n};\n\ntype IntlWithSegmenter = typeof Intl & {\n Segmenter?: new (locales?: string | string[], options?: Intl.SegmenterOptions) => Intl.Segmenter;\n};\n\nconst localeKey = (locale: string | string[] | undefined): string =>\n locale === undefined ? '' : Array.isArray(locale) ? locale.join('\\0') : locale;\n\nconst segmenterCache = new Map<string, Intl.Segmenter>();\n\nconst getSegmenter = (\n locale: string | string[] | undefined,\n granularity: 'grapheme' | 'word',\n): Intl.Segmenter | null => {\n if (typeof Intl === 'undefined') return null;\n\n const Seg = (Intl as IntlWithSegmenter).Segmenter;\n\n if (typeof Seg !== 'function') return null;\n\n const key = `${granularity}:${localeKey(locale)}`;\n let segmenter = segmenterCache.get(key);\n\n if (!segmenter) {\n segmenter = new Seg(locale, { granularity });\n segmenterCache.set(key, segmenter);\n }\n\n return segmenter;\n};\n\nconst splitIntoGraphemes = (text: string, locale?: string | string[]): string[] => {\n const segmenter = getSegmenter(locale, 'grapheme');\n\n if (segmenter) {\n return Array.from(segmenter.segment(text), (s: Intl.SegmentData) => s.segment);\n }\n\n // Fallback: Array.from does not preserve all ZWJ/emoji grapheme clusters.\n // Remove when the browser baseline requires Intl.Segmenter.\n return Array.from(text);\n};\n\nconst isWhitespaceGrapheme = (ch: string): boolean => /^\\s+$/u.test(ch);\n\nconst countCharGraphemes = (text: string, locale?: string | string[]): number =>\n splitIntoGraphemes(text, locale).filter((ch) => !isWhitespaceGrapheme(ch)).length;\n\ntype WordSegment = Intl.SegmentData;\n\nconst segmentWords = (text: string, locale?: string | string[]): WordSegment[] => {\n const segmenter = getSegmenter(locale, 'word');\n\n if (segmenter) {\n return Array.from(segmenter.segment(text));\n }\n\n // Fallback: whitespace splitting is not locale-aware and keeps punctuation attached to tokens.\n // Remove when the browser baseline requires Intl.Segmenter.\n const words = text.split(/\\s+/u).filter(Boolean);\n const segments: WordSegment[] = [];\n\n let cursor = 0;\n\n for (const word of words) {\n const start = text.indexOf(word, cursor);\n\n if (start > cursor) {\n segments.push({\n segment: text.slice(cursor, start),\n index: cursor,\n input: text,\n isWordLike: false,\n });\n }\n\n segments.push({ segment: word, index: start, input: text, isWordLike: true });\n cursor = start + word.length;\n }\n\n if (cursor < text.length) {\n segments.push({ segment: text.slice(cursor), index: cursor, input: text, isWordLike: false });\n }\n\n return segments;\n};\n\nconst countWords = (text: string, locale?: string | string[]): number =>\n segmentWords(text, locale).filter((s) => s.isWordLike).length;\n\nconst emptyElement = (el: HTMLElement): void => {\n el.replaceChildren();\n};\n\nconst isHTMLElement = (el: unknown): el is HTMLElement =>\n !!el && typeof HTMLElement !== 'undefined' && el instanceof HTMLElement;\n\ntype NonUndefined<T> = T extends undefined ? never : T;\ntype OmitUndefined<T extends Record<string, unknown>> = {\n [K in keyof T as T[K] extends undefined ? never : K]: NonUndefined<T[K]>;\n};\n\nconst omitUndefined = <T extends Record<string, unknown>>(obj: T): OmitUndefined<T> => {\n const out = {} as OmitUndefined<T>;\n\n (Object.keys(obj) as Array<keyof T>).forEach((key) => {\n const val = obj[key];\n\n if (val !== undefined) {\n (out as Record<string, unknown>)[key as string] = val as unknown;\n }\n });\n\n return out;\n};\n\ntype RuntimeOptionPatch = Partial<Omit<TextSlicerOptions, 'container'>>;\n\nconst mergeRuntimeOptions = (base: RuntimeOptions, patch: RuntimeOptionPatch): RuntimeOptions => {\n const { container: _container, ...runtimeOptions } = patch as TextSlicerOptions;\n\n return {\n ...base,\n ...omitUndefined(runtimeOptions as Record<string, unknown>),\n };\n};\n\ntype ManagedStyle = { value: string; priority: string };\n\nexport class TextSlicer {\n private readonly el: HTMLElement | null;\n private original: string;\n private opts: RuntimeOptions;\n private callbacks: TextSlicerCallbacks | undefined;\n private charIndex: number;\n private mounted: boolean;\n private resizeObserver?: ResizeObserver;\n private managedStyles = new Map<string, ManagedStyle>();\n private managedAttributes = new Map<string, string | null>();\n\n constructor(options: TextSlicerOptions = {}, callbacks?: TextSlicerCallbacks) {\n const { container, ...runtimeOptions } = options;\n const el = resolveContainer(container);\n this.el = el;\n // Plain-text mode intentionally discards nested markup. Upgrade path:\n // walk text nodes and preserve element boundaries in a DOM-preserving mode.\n this.original = isHTMLElement(el) ? (el.textContent?.toString() ?? '') : '';\n this.opts = mergeRuntimeOptions(DEFAULT_OPTIONS, runtimeOptions);\n\n this.callbacks = callbacks;\n this.charIndex = 0;\n this.mounted = false;\n }\n\n get metrics(): TextSlicerMetrics {\n const text = this.original;\n const { locale } = this.opts;\n\n return {\n wordTotal: text.length ? countWords(text, locale) : 0,\n charTotal: text.length ? countCharGraphemes(text, locale) : 0,\n renderedAt: Date.now(),\n };\n }\n\n init(): void {\n if (!this.el) return;\n\n this.mounted = true;\n this.split();\n this.syncHeightObserver();\n }\n\n reinit(newText?: string, next?: RuntimeOptionPatch): void {\n if (!this.el) return;\n if (typeof newText === 'string') this.original = newText;\n if (next) this.opts = mergeRuntimeOptions(this.opts, next);\n\n this.mounted = true;\n this.split();\n this.syncHeightObserver();\n }\n\n clear(): void {\n if (!this.el) return;\n\n emptyElement(this.el);\n this.restoreManagedAttribute('aria-label');\n }\n\n split(): void {\n if (!this.el) return;\n\n emptyElement(this.el);\n this.charIndex = 0;\n\n const text = this.original;\n const fragment = document.createDocumentFragment();\n\n if (this.opts.splitMode === 'chars') {\n this.appendChars(fragment, text);\n } else {\n this.appendWords(fragment, text);\n }\n\n this.el.appendChild(fragment);\n this.syncAccessibleLabel(text);\n\n const metrics = this.metrics;\n\n if (this.opts.cssVariables) {\n this.setManagedStyle(CSS_VAR_WORD_TOTAL, String(metrics.wordTotal));\n this.setManagedStyle(CSS_VAR_CHAR_TOTAL, String(metrics.charTotal));\n } else {\n this.restoreManagedStyle(CSS_VAR_WORD_TOTAL);\n this.restoreManagedStyle(CSS_VAR_CHAR_TOTAL);\n }\n\n this.callbacks?.onAfterRender?.(metrics);\n }\n\n destroy(): void {\n if (!this.el) return;\n\n this.syncHeightObserver(false);\n this.restoreManagedStyles();\n this.restoreManagedAttribute('aria-label');\n this.el.textContent = this.original;\n this.mounted = false;\n }\n\n updateOptions(next: RuntimeOptionPatch): void {\n this.opts = mergeRuntimeOptions(this.opts, next);\n\n if (this.mounted) {\n this.split();\n this.syncHeightObserver();\n }\n }\n\n lockHeight(): void {\n if (!this.el) return;\n\n const h = this.measureHeight();\n\n if (h > 0) {\n this.setManagedStyle('height', `${h}px`);\n }\n }\n\n unlockHeight(): void {\n this.restoreManagedStyle('height');\n }\n\n private appendWords(fragment: DocumentFragment, text: string): void {\n const segments = segmentWords(text, this.opts.locale);\n let wordIndex = 0;\n\n for (const { segment, isWordLike } of segments) {\n if (isWordLike) {\n const wordSpan = this.createWordSpan(wordIndex, segment);\n\n if (this.opts.splitMode === 'both') {\n this.appendGraphemes(wordSpan, segment);\n } else {\n wordSpan.append(document.createTextNode(segment));\n }\n\n fragment.append(wordSpan);\n wordIndex += 1;\n } else if (isWhitespaceGrapheme(segment)) {\n if (this.opts.splitMode === 'both') {\n this.appendGraphemes(fragment, segment);\n } else {\n fragment.append(this.createWhitespaceSpan(segment));\n }\n } else if (segment.length > 0) {\n if (this.opts.splitMode === 'both') {\n this.appendGraphemes(fragment, segment);\n } else {\n fragment.append(this.createHiddenTextSpan(segment));\n }\n }\n }\n }\n\n private appendChars(fragment: DocumentFragment, text: string): void {\n for (const ch of splitIntoGraphemes(text, this.opts.locale)) {\n this.appendGrapheme(fragment, ch);\n }\n }\n\n private appendGraphemes(parent: DocumentFragment | HTMLElement, text: string): void {\n for (const ch of splitIntoGraphemes(text, this.opts.locale)) {\n this.appendGrapheme(parent, ch);\n }\n }\n\n private appendGrapheme(parent: DocumentFragment | HTMLElement, ch: string): void {\n if (isWhitespaceGrapheme(ch)) {\n if (this.opts.keepWhitespaceNodes) {\n parent.append(this.createWhitespaceSpan(ch));\n } else {\n parent.append(document.createTextNode(ch));\n }\n\n return;\n }\n\n parent.append(this.createCharSpan(ch));\n }\n\n private createWordSpan(index: number, word: string): HTMLSpanElement {\n const span = document.createElement('span');\n\n span.classList.add(CLASSNAMES.word);\n span.setAttribute('aria-hidden', 'true');\n\n if (this.opts.dataAttributes) {\n span.setAttribute('data-word', word);\n }\n\n if (this.opts.cssVariables) {\n span.style.setProperty(CSS_VAR_WORD_INDEX, String(index));\n }\n\n return span;\n }\n\n private createCharSpan(ch: string): HTMLSpanElement {\n const span = document.createElement('span');\n\n span.textContent = ch;\n span.setAttribute('aria-hidden', 'true');\n span.classList.add(CLASSNAMES.char);\n\n if (this.opts.dataAttributes) span.setAttribute('data-char', ch);\n\n if (this.opts.cssVariables) {\n span.style.setProperty(CSS_VAR_CHAR_INDEX, String(this.charIndex));\n }\n\n this.charIndex += 1;\n\n return span;\n }\n\n private createWhitespaceSpan(text: string): HTMLSpanElement {\n const span = document.createElement('span');\n\n span.classList.add(CLASSNAMES.whitespace);\n span.textContent = text;\n span.setAttribute('aria-hidden', 'true');\n\n return span;\n }\n\n private createHiddenTextSpan(text: string): HTMLSpanElement {\n const span = document.createElement('span');\n\n span.textContent = text;\n span.setAttribute('aria-hidden', 'true');\n\n return span;\n }\n\n private syncAccessibleLabel(text: string): void {\n if (!this.el) return;\n\n if (this.managedAttributes.has('aria-label')) {\n this.setManagedAttribute('aria-label', text);\n return;\n }\n\n if (this.el.hasAttribute('aria-label') || this.el.hasAttribute('aria-labelledby')) {\n return;\n }\n\n this.setManagedAttribute('aria-label', text);\n }\n\n private measureHeight(): number {\n if (!this.el) return 0;\n\n this.el.classList.add(MEASURING_CLASS);\n\n try {\n void this.el.offsetHeight;\n\n let h = this.el.offsetHeight || this.el.clientHeight || 0;\n\n if (!h) {\n h = Math.round(this.el.getBoundingClientRect().height);\n }\n\n return Math.max(0, Math.ceil(h));\n } finally {\n this.el.classList.remove(MEASURING_CLASS);\n }\n }\n\n private syncHeightObserver(enable: boolean = this.opts.containerHeightVar): void {\n if (!this.el) return;\n\n if (enable) {\n if (typeof ResizeObserver !== 'function') {\n this.restoreManagedStyle(CSS_VAR_CONTAINER_HEIGHT);\n return;\n }\n\n if (!this.resizeObserver) {\n this.resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n\n if (!entry || !this.el) return;\n\n const boxSize = entry.borderBoxSize?.[0]?.blockSize;\n const h = Math.max(0, Math.ceil(boxSize ?? entry.contentRect.height));\n\n if (h > 0) {\n this.setManagedStyle(CSS_VAR_CONTAINER_HEIGHT, `${h}px`);\n }\n });\n\n this.resizeObserver.observe(this.el);\n }\n } else if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = undefined;\n this.restoreManagedStyle(CSS_VAR_CONTAINER_HEIGHT);\n }\n }\n\n private setManagedStyle(property: string, value: string): void {\n if (!this.el) return;\n\n if (!this.managedStyles.has(property)) {\n this.managedStyles.set(property, {\n value: this.el.style.getPropertyValue(property),\n priority: this.el.style.getPropertyPriority(property),\n });\n }\n\n this.el.style.setProperty(property, value);\n }\n\n private restoreManagedStyle(property: string): void {\n if (!this.el) return;\n\n const previous = this.managedStyles.get(property);\n\n if (previous === undefined) return;\n\n if (previous.value) {\n this.el.style.setProperty(property, previous.value, previous.priority);\n } else {\n this.el.style.removeProperty(property);\n }\n\n this.managedStyles.delete(property);\n }\n\n private restoreManagedStyles(): void {\n for (const property of [...this.managedStyles.keys()]) {\n this.restoreManagedStyle(property);\n }\n }\n\n private setManagedAttribute(name: string, value: string): void {\n if (!this.el) return;\n\n if (!this.managedAttributes.has(name)) {\n this.managedAttributes.set(name, this.el.getAttribute(name));\n }\n\n this.el.setAttribute(name, value);\n }\n\n private restoreManagedAttribute(name: string): void {\n if (!this.el || !this.managedAttributes.has(name)) return;\n\n const previous = this.managedAttributes.get(name);\n\n if (previous === null) {\n this.el.removeAttribute(name);\n } else if (previous !== undefined) {\n this.el.setAttribute(name, previous);\n }\n\n this.managedAttributes.delete(name);\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "text-slicer",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Create word and grapheme-level DOM hooks from plain text for animation and styling.",
|
|
5
5
|
"author": "ux-ui.pro",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"@ux-ui/biome-config": "^0.1.0",
|
|
61
61
|
"@ux-ui/tsconfig-base": "^0.1.0",
|
|
62
62
|
"@ux-ui/tsdown-config": "^0.1.0",
|
|
63
|
+
"jsdom": "29.1.1",
|
|
63
64
|
"publint": "^0.3.21",
|
|
64
65
|
"rimraf": "6.1.3",
|
|
65
66
|
"tsdown": "0.22.3",
|