From 63bc558a5502d4f1e807c2568a72daf57345981a Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 24 Jun 2022 11:16:34 +0200 Subject: [PATCH] Moves helper function `h` to base/browser/dom --- src/vs/base/browser/dom.ts | 96 +++++++++++++++++++ .../contrib/mergeEditor/browser/utils.ts | 81 ---------------- .../browser/view/editors/codeEditorView.ts | 3 +- .../view/editors/inputCodeEditorView.ts | 6 +- 4 files changed, 101 insertions(+), 85 deletions(-) diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index c323e74ddfc..88afb682b93 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1761,3 +1761,99 @@ export function computeClippingRect(elementOrRect: HTMLElement | DOMRectReadOnly return { top, right, bottom, left }; } + +/** + * A helper function to create nested dom nodes. + * + * + * ```ts + * private readonly htmlElements = h('div.code-view', [ + * h('div.title', { $: 'title' }), + * h('div.container', [ + * h('div.gutter', { $: 'gutterDiv' }), + * h('div', { $: 'editor' }), + * ]), + * ]); + * private readonly editor = createEditor(this.htmlElements.editor); + * ``` +*/ +export function h(tag: TTag): never; +export function h( + tag: TTag, + attributes: { $: TId } +): Record>; +export function h)[]>( + tag: TTag, + children: T +): (ArrayToObj & Record<'root', TagToElement>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; +export function h)[]>( + tag: TTag, + attributes: { $: TId }, + children: T +): (ArrayToObj & Record>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; +export function h(tag: string, ...args: [] | [attributes: { $: string } | Record, children?: any[]] | [children: any[]]): Record { + let attributes: Record; + let children: (Record | HTMLElement)[] | undefined; + + if (Array.isArray(args[0])) { + attributes = {}; + children = args[0]; + } else { + attributes = args[0] as any || {}; + children = args[1]; + } + + const [tagName, className] = tag.split('.'); + const el = document.createElement(tagName); + if (className) { + el.className = className; + } + + const result: Record = {}; + + if (children) { + for (const c of children) { + if (c instanceof HTMLElement) { + el.appendChild(c); + } else if (typeof c === 'string') { + el.append(c); + } else { + Object.assign(result, c); + el.appendChild(c.root); + } + } + } + + for (const [key, value] of Object.entries(attributes)) { + if (key === '$') { + result[value] = el; + continue; + } + el.setAttribute(key, value); + } + + result['root'] = el; + + return result; +} + +type RemoveHTMLElement = T extends HTMLElement ? never : T; + +type ArrayToObj = UnionToIntersection>; + + +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; + +type HTMLElementsByTagName = { + div: HTMLDivElement; + span: HTMLSpanElement; + a: HTMLAnchorElement; +}; + +type TagToElement = T extends `${infer TStart}.${string}` + ? TStart extends keyof HTMLElementsByTagName + ? HTMLElementsByTagName[TStart] + : HTMLElement + : T extends keyof HTMLElementsByTagName + ? HTMLElementsByTagName[T] + : HTMLElement; diff --git a/src/vs/workbench/contrib/mergeEditor/browser/utils.ts b/src/vs/workbench/contrib/mergeEditor/browser/utils.ts index 0dcc01bc751..308b6ab01ff 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/utils.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/utils.ts @@ -53,87 +53,6 @@ export class ReentrancyBarrier { } } -export function h(tag: TTag): never; -export function h( - tag: TTag, - attributes: { $: TId } -): Record>; -export function h)[]>( - tag: TTag, - children: T -): (ArrayToObj & Record<'root', TagToElement>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; -export function h)[]>( - tag: TTag, - attributes: { $: TId }, - children: T -): (ArrayToObj & Record>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never; -export function h(tag: string, ...args: [] | [attributes: { $: string } | Record, children?: any[]] | [children: any[]]): Record { - let attributes: Record; - let children: (Record | HTMLElement)[] | undefined; - - if (Array.isArray(args[0])) { - attributes = {}; - children = args[0]; - } else { - attributes = args[0] as any || {}; - children = args[1]; - } - - const [tagName, className] = tag.split('.'); - const el = document.createElement(tagName); - if (className) { - el.className = className; - } - - const result: Record = {}; - - if (children) { - for (const c of children) { - if (c instanceof HTMLElement) { - el.appendChild(c); - } else if (typeof c === 'string') { - el.append(c); - } else { - Object.assign(result, c); - el.appendChild(c.root); - } - } - } - - for (const [key, value] of Object.entries(attributes)) { - if (key === '$') { - result[value] = el; - continue; - } - el.setAttribute(key, value); - } - - result['root'] = el; - - return result; -} - -type RemoveHTMLElement = T extends HTMLElement ? never : T; - -type ArrayToObj = UnionToIntersection>; - - -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; - -type HTMLElementsByTagName = { - div: HTMLDivElement; - span: HTMLSpanElement; - a: HTMLAnchorElement; -}; - -type TagToElement = T extends `${infer TStart}.${string}` - ? TStart extends keyof HTMLElementsByTagName - ? HTMLElementsByTagName[TStart] - : HTMLElement - : T extends keyof HTMLElementsByTagName - ? HTMLElementsByTagName[T] - : HTMLElement; - export function setStyle( element: HTMLElement, style: { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts index c58038a129c..64d1b22f905 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { h } from 'vs/base/browser/dom'; import { IView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { Emitter, Event } from 'vs/base/common/event'; @@ -12,7 +13,7 @@ import { ITextModel } from 'vs/editor/common/model'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { DEFAULT_EDITOR_MAX_DIMENSIONS, DEFAULT_EDITOR_MIN_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; import { IObservable, observableFromEvent, ObservableValue } from 'vs/workbench/contrib/audioCues/browser/observable'; -import { h, setStyle } from 'vs/workbench/contrib/mergeEditor/browser/utils'; +import { setStyle } from 'vs/workbench/contrib/mergeEditor/browser/utils'; import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel'; export interface ICodeEditorViewOptions { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index 412d6cfca63..d77432927b1 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -14,7 +14,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { autorun, derivedObservable, IObservable, ITransaction, ObservableValue, transaction } from 'vs/workbench/contrib/audioCues/browser/observable'; import { InputState, ModifiedBaseRangeState } from 'vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange'; -import { applyObservableDecorations, h, setFields } from 'vs/workbench/contrib/mergeEditor/browser/utils'; +import { applyObservableDecorations, setFields } from 'vs/workbench/contrib/mergeEditor/browser/utils'; import { handledConflictMinimapOverViewRulerColor, unhandledConflictMinimapOverViewRulerColor } from 'vs/workbench/contrib/mergeEditor/browser/view/colors'; import { EditorGutter, IGutterItemInfo, IGutterItemView } from '../editorGutter'; import { CodeEditorView, ICodeEditorViewOptions } from './codeEditorView'; @@ -270,9 +270,9 @@ export class MergeConflictGutterItemView extends Disposable implements IGutterIt }); })); - target.appendChild(h('div.background', [noBreakWhitespace]).root); + target.appendChild(dom.h('div.background', [noBreakWhitespace]).root); target.appendChild( - h('div.checkbox', [h('div.checkbox-background', [checkBox.domNode])]).root + dom.h('div.checkbox', [dom.h('div.checkbox-background', [checkBox.domNode])]).root ); }