feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2019, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* The namespace for clipboard related functionality.
*/
export namespace ClipboardExt {
/**
* Copy text to the system clipboard.
*
* @param text - The text to copy to the clipboard.
*/
export function copyText(text: string): void {
// Fetch the document body.
const { body } = document;
// Set up the clipboard event listener.
const handler = (event: ClipboardEvent) => {
// Stop the event propagation.
event.preventDefault();
event.stopPropagation();
// Set the clipboard data.
event.clipboardData!.setData('text', text);
// Remove the event listener.
body.removeEventListener('copy', handler, true);
};
// Add the event listener.
body.addEventListener('copy', handler, true);
// Trigger the event.
document.execCommand('copy');
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* The namespace for element related utilities.
*/
export namespace ElementExt {
/**
* An object which holds the border and padding data for an element.
*/
export interface IBoxSizing {
/**
* The top border width, in pixels.
*/
borderTop: number;
/**
* The left border width, in pixels.
*/
borderLeft: number;
/**
* The right border width, in pixels.
*/
borderRight: number;
/**
* The bottom border width, in pixels.
*/
borderBottom: number;
/**
* The top padding width, in pixels.
*/
paddingTop: number;
/**
* The left padding width, in pixels.
*/
paddingLeft: number;
/**
* The right padding width, in pixels.
*/
paddingRight: number;
/**
* The bottom padding width, in pixels.
*/
paddingBottom: number;
/**
* The sum of horizontal border and padding.
*/
horizontalSum: number;
/**
* The sum of vertical border and padding.
*/
verticalSum: number;
}
/**
* Compute the box sizing for an element.
*
* @param element - The element of interest.
*
* @returns The box sizing data for the specified element.
*/
export function boxSizing(element: Element): IBoxSizing {
const style = window.getComputedStyle(element);
const bt = parseFloat(style.borderTopWidth!) || 0;
const bl = parseFloat(style.borderLeftWidth!) || 0;
const br = parseFloat(style.borderRightWidth!) || 0;
const bb = parseFloat(style.borderBottomWidth!) || 0;
const pt = parseFloat(style.paddingTop!) || 0;
const pl = parseFloat(style.paddingLeft!) || 0;
const pr = parseFloat(style.paddingRight!) || 0;
const pb = parseFloat(style.paddingBottom!) || 0;
const hs = bl + pl + pr + br;
const vs = bt + pt + pb + bb;
return {
borderTop: bt,
borderLeft: bl,
borderRight: br,
borderBottom: bb,
paddingTop: pt,
paddingLeft: pl,
paddingRight: pr,
paddingBottom: pb,
horizontalSum: hs,
verticalSum: vs,
};
}
/**
* An object which holds the min and max size data for an element.
*/
export interface ISizeLimits {
/**
* The minimum width, in pixels.
*/
minWidth: number;
/**
* The minimum height, in pixels.
*/
minHeight: number;
/**
* The maximum width, in pixels.
*/
maxWidth: number;
/**
* The maximum height, in pixels.
*/
maxHeight: number;
}
/**
* Compute the size limits for an element.
*
* @param element - The element of interest.
*
* @returns The size limit data for the specified element.
*/
export function sizeLimits(element: Element): ISizeLimits {
const style = window.getComputedStyle(element);
const minWidth = parseFloat(style.minWidth!) || 0;
const minHeight = parseFloat(style.minHeight!) || 0;
let maxWidth = parseFloat(style.maxWidth!) || Infinity;
let maxHeight = parseFloat(style.maxHeight!) || Infinity;
maxWidth = Math.max(minWidth, maxWidth);
maxHeight = Math.max(minHeight, maxHeight);
return { minWidth, minHeight, maxWidth, maxHeight };
}
/**
* Test whether a client position lies within an element.
*
* @param element - The DOM element of interest.
*
* @param clientX - The client X coordinate of interest.
*
* @param clientY - The client Y coordinate of interest.
*
* @returns Whether the point is within the given element.
*/
export function hitTest(
element: Element,
clientX: number,
clientY: number,
): boolean {
const rect = element.getBoundingClientRect();
return (
clientX >= rect.left &&
clientX < rect.right &&
clientY >= rect.top &&
clientY < rect.bottom
);
}
/**
* Vertically scroll an element into view if needed.
*
* @param area - The scroll area element.
*
* @param element - The element of interest.
*
* #### Notes
* This follows the "nearest" behavior of the native `scrollIntoView`
* method, which is not supported by all browsers.
* https://drafts.csswg.org/cssom-view/#element-scrolling-members
*
* If the element fully covers the visible area or is fully contained
* within the visible area, no scrolling will take place. Otherwise,
* the nearest edges of the area and element are aligned.
*/
export function scrollIntoViewIfNeeded(
area: Element,
element: Element,
): void {
const ar = area.getBoundingClientRect();
const er = element.getBoundingClientRect();
if (er.top <= ar.top && er.bottom >= ar.bottom) {
return;
}
if (er.top < ar.top && er.height <= ar.height) {
area.scrollTop -= ar.top - er.top;
return;
}
if (er.bottom > ar.bottom && er.height >= ar.height) {
area.scrollTop -= ar.top - er.top;
return;
}
if (er.top < ar.top && er.height > ar.height) {
area.scrollTop -= ar.bottom - er.bottom;
return;
}
if (er.bottom > ar.bottom && er.height < ar.height) {
area.scrollTop -= ar.bottom - er.bottom;
return;
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* @packageDocumentation
* @module domutils
*/
export * from './clipboard';
export * from './element';
export * from './platform';
export * from './selector';

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* The namespace for platform related utilities.
*/
export namespace Platform {
/**
* A flag indicating whether the platform is Mac.
*/
export const IS_MAC = !!navigator.platform.match(/Mac/i);
/**
* A flag indicating whether the platform is Windows.
*/
export const IS_WIN = !!navigator.platform.match(/Win/i);
/**
* A flag indicating whether the browser is IE.
*/
export const IS_IE = /Trident/.test(navigator.userAgent);
/**
* A flag indicating whether the browser is Edge.
*/
export const IS_EDGE = /Edge/.test(navigator.userAgent);
/**
* Test whether the `accel` key is pressed.
*
* @param event - The keyboard or mouse event of interest.
*
* @returns Whether the `accel` key is pressed.
*
* #### Notes
* On Mac the `accel` key is the command key. On all other
* platforms the `accel` key is the control key.
*/
export function accelKey(event: KeyboardEvent | MouseEvent): boolean {
return IS_MAC ? event.metaKey : event.ctrlKey;
}
}

View File

@@ -0,0 +1,281 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
/**
* The namespace for selector related utilities.
*/
export namespace Selector {
/**
* Calculate the specificity of a single CSS selector.
*
* @param selector - The CSS selector of interest.
*
* @returns The specificity of the selector.
*
* #### Undefined Behavior
* The selector is invalid.
*
* #### Notes
* This is based on https://www.w3.org/TR/css3-selectors/#specificity
*
* A larger number represents a more specific selector.
*
* The smallest possible specificity is `0`.
*
* The result is represented as a hex number `0x<aa><bb><cc>` where
* each component is the count of the respective selector clause.
*
* If the selector contains commas, only the first clause is used.
*
* The computed result is cached, so subsequent calculations for the
* same selector are extremely fast.
*/
export function calculateSpecificity(selector: string): number {
if (selector in Private.specificityCache) {
return Private.specificityCache[selector];
}
const result = Private.calculateSingle(selector);
return (Private.specificityCache[selector] = result);
}
/**
* Test whether a selector is a valid CSS selector.
*
* @param selector - The CSS selector of interest.
*
* @returns `true` if the selector is valid, `false` otherwise.
*
* #### Notes
* The computed result is cached, so subsequent tests for the same
* selector are extremely fast.
*/
export function isValid(selector: string): boolean {
if (selector in Private.validityCache) {
return Private.validityCache[selector];
}
let result = true;
try {
Private.testElem.querySelector(selector);
} catch (err) {
result = false;
}
return (Private.validityCache[selector] = result);
}
/**
* Test whether an element matches a CSS selector.
*
* @param element - The element of interest.
*
* @param selector - The valid CSS selector of interest.
*
* @returns `true` if the element is a match, `false` otherwise.
*
* #### Notes
* This function uses the builtin browser capabilities when possible,
* falling back onto a document query otherwise.
*/
export function matches(element: Element, selector: string): boolean {
return Private.protoMatchFunc.call(element, selector);
}
}
/**
* The namespace for the module implementation details.
*/
namespace Private {
/**
* A type alias for an object hash.
*/
export interface StringMap<T> {
[key: string]: T;
}
/**
* A cache of computed selector specificity values.
*/
export const specificityCache: StringMap<number> = Object.create(null);
/**
* A cache of computed selector validity.
*/
export const validityCache: StringMap<boolean> = Object.create(null);
/**
* An empty element for testing selector validity.
*/
export const testElem = document.createElement('div');
/**
* A cross-browser CSS selector matching prototype function.
*/
export const protoMatchFunc = (() => {
const proto = Element.prototype as any;
return (
proto.matches ||
proto.matchesSelector ||
proto.mozMatchesSelector ||
proto.msMatchesSelector ||
proto.oMatchesSelector ||
proto.webkitMatchesSelector ||
function (selector: string) {
// @ts-expect-error
const elem = this as Element;
const matches = elem.ownerDocument
? elem.ownerDocument.querySelectorAll(selector)
: [];
return Array.prototype.indexOf.call(matches, elem) !== -1;
}
);
})();
/**
* Calculate the specificity of a single selector.
*
* The behavior is undefined if the selector is invalid.
*/
export function calculateSingle(selector: string): number {
// Ignore anything after the first comma.
selector = selector.split(',', 1)[0];
// Setup the aggregate counters.
let a = 0;
let b = 0;
let c = 0;
// Apply a regex to the front of the selector. If it succeeds, that
// portion of the selector is removed. Returns a success/fail flag.
function match(re: RegExp): boolean {
const match = selector.match(re);
if (match === null) {
return false;
}
selector = selector.slice(match[0].length);
return true;
}
// Replace the negation pseudo-class (which is ignored),
// but keep its inner content (which is not ignored).
selector = selector.replace(NEGATION_RE, ' $1 ');
// Continue matching until the selector is consumed.
while (selector.length > 0) {
// Match an ID selector.
if (match(ID_RE)) {
a++;
continue;
}
// Match a class selector.
if (match(CLASS_RE)) {
b++;
continue;
}
// Match an attribute selector.
if (match(ATTR_RE)) {
b++;
continue;
}
// Match a pseudo-element selector. This is done before matching
// a pseudo-class since this regex overlaps with that regex.
if (match(PSEUDO_ELEM_RE)) {
c++;
continue;
}
// Match a pseudo-class selector.
if (match(PSEDUO_CLASS_RE)) {
b++;
continue;
}
// Match a plain type selector.
if (match(TYPE_RE)) {
c++;
continue;
}
// Finally, match any ignored characters.
if (match(IGNORE_RE)) {
continue;
}
// At this point, the selector is assumed to be invalid.
return 0;
}
// Clamp each component to a reasonable base.
a = Math.min(a, 0xff);
b = Math.min(b, 0xff);
c = Math.min(c, 0xff);
// Combine the components into a single result.
return (a << 16) | (b << 8) | c;
}
/**
* A regex which matches an ID selector at string start.
*/
const ID_RE = /^#[^\s\+>~#\.\[:]+/;
/**
* A regex which matches a class selector at string start.
*/
const CLASS_RE = /^\.[^\s\+>~#\.\[:]+/;
/**
* A regex which matches an attribute selector at string start.
*/
const ATTR_RE = /^\[[^\]]+\]/;
/**
* A regex which matches a type selector at string start.
*/
const TYPE_RE = /^[^\s\+>~#\.\[:]+/;
/**
* A regex which matches a pseudo-element selector at string start.
*/
const PSEUDO_ELEM_RE =
/^(::[^\s\+>~#\.\[:]+|:first-line|:first-letter|:before|:after)/;
/**
* A regex which matches a pseudo-class selector at string start.
*/
const PSEDUO_CLASS_RE = /^:[^\s\+>~#\.\[:]+/;
/**
* A regex which matches ignored characters at string start.
*/
const IGNORE_RE = /^[\s\+>~\*]+/;
/**
* A regex which matches the negation pseudo-class globally.
*/
const NEGATION_RE = /:not\(([^\)]+)\)/g;
}