feat: initial commit - Phase 1 & 2 core features

This commit is contained in:
hiderfong
2026-04-22 17:07:33 +08:00
commit 1773bda06b
25005 changed files with 6252106 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
import { SFCWithInstall } from "../../utils/vue/typescript.js";
import "../../utils/index.js";
import { AffixEmits, AffixInstance, AffixProps, AffixPropsPublic, affixEmits, affixProps } from "./src/affix.js";
import { _default } from "./src/affix.vue.js";
//#region ../../packages/components/affix/index.d.ts
declare const ElAffix: SFCWithInstall<typeof _default>;
//#endregion
export { AffixEmits, AffixInstance, AffixProps, AffixPropsPublic, ElAffix, ElAffix as default, affixEmits, affixProps };
+10
View File
@@ -0,0 +1,10 @@
import { withInstall } from "../../utils/vue/install.mjs";
import { affixEmits, affixProps } from "./src/affix.mjs";
import affix_default from "./src/affix2.mjs";
//#region ../../packages/components/affix/index.ts
const ElAffix = withInstall(affix_default);
//#endregion
export { ElAffix, ElAffix as default, affixEmits, affixProps };
//# sourceMappingURL=index.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","names":["Affix"],"sources":["../../../../../packages/components/affix/index.ts"],"sourcesContent":["import { withInstall } from '@element-plus/utils'\nimport Affix from './src/affix.vue'\n\nimport type { SFCWithInstall } from '@element-plus/utils'\n\nexport const ElAffix: SFCWithInstall<typeof Affix> = withInstall(Affix)\nexport default ElAffix\n\nexport * from './src/affix'\n"],"mappings":";;;;;AAKA,MAAa,UAAwC,YAAYA,cAAM"}
+63
View File
@@ -0,0 +1,63 @@
import { EpPropFinalized, EpPropMergeType } from "../../../utils/vue/props/types.js";
import { ZIndexType } from "../../../utils/typescript.js";
import "../../../utils/index.js";
import { _default } from "./affix.vue.js";
import { ExtractPublicPropTypes } from "vue";
import * as csstype from "csstype";
//#region ../../packages/components/affix/src/affix.d.ts
interface AffixProps {
/**
* @description affix element zIndex value
* */
zIndex?: ZIndexType;
/**
* @description target container. (CSS selector)
*/
target?: string;
/**
* @description offset distance
* */
offset?: number;
/**
* @description position of affix
* */
position?: 'top' | 'bottom';
/**
* @description whether affix element is teleported, if `true` it will be teleported to where `append-to` sets
* */
teleported?: boolean;
/**
* @description which element the affix element appends to
* */
appendTo?: string | HTMLElement;
}
/**
* @deprecated Removed after 3.0.0, Use `AffixProps` instead.
*/
declare const affixProps: {
readonly zIndex: EpPropFinalized<(new (...args: any[]) => string | number) | (() => csstype.Property.ZIndex | undefined) | (((new (...args: any[]) => string | number) | (() => csstype.Property.ZIndex | undefined)) | null)[], unknown, unknown, 100, boolean>;
readonly target: EpPropFinalized<StringConstructor, unknown, unknown, "", boolean>;
readonly offset: EpPropFinalized<NumberConstructor, unknown, unknown, 0, boolean>;
readonly position: EpPropFinalized<StringConstructor, "top" | "bottom", unknown, "top", boolean>;
readonly teleported: BooleanConstructor;
readonly appendTo: EpPropFinalized<(new (...args: any[]) => string | HTMLElement) | (() => EpPropMergeType<(new (...args: any[]) => string | HTMLElement) | (() => string | HTMLElement) | (((new (...args: any[]) => string | HTMLElement) | (() => string | HTMLElement)) | null)[], unknown, unknown>) | (((new (...args: any[]) => string | HTMLElement) | (() => EpPropMergeType<(new (...args: any[]) => string | HTMLElement) | (() => string | HTMLElement) | (((new (...args: any[]) => string | HTMLElement) | (() => string | HTMLElement)) | null)[], unknown, unknown>)) | null)[], unknown, unknown, "body", boolean>;
};
/**
* @deprecated Removed after 3.0.0, Use `AffixProps` instead.
*/
type AffixPropsPublic = ExtractPublicPropTypes<typeof affixProps>;
declare const affixEmits: {
scroll: ({
scrollTop,
fixed
}: {
scrollTop: number;
fixed: boolean;
}) => boolean;
change: (fixed: boolean) => boolean;
};
type AffixEmits = typeof affixEmits;
type AffixInstance = InstanceType<typeof _default> & unknown;
//#endregion
export { AffixEmits, AffixInstance, AffixProps, AffixPropsPublic, affixEmits, affixProps };
+41
View File
@@ -0,0 +1,41 @@
import { CHANGE_EVENT } from "../../../constants/event.mjs";
import { isBoolean, isNumber } from "../../../utils/types.mjs";
import { buildProps, definePropType } from "../../../utils/vue/props/runtime.mjs";
import { teleportProps } from "../../teleport/src/teleport.mjs";
//#region ../../packages/components/affix/src/affix.ts
/**
* @deprecated Removed after 3.0.0, Use `AffixProps` instead.
*/
const affixProps = buildProps({
zIndex: {
type: definePropType([Number, String]),
default: 100
},
target: {
type: String,
default: ""
},
offset: {
type: Number,
default: 0
},
position: {
type: String,
values: ["top", "bottom"],
default: "top"
},
teleported: Boolean,
appendTo: {
type: teleportProps.to.type,
default: "body"
}
});
const affixEmits = {
scroll: ({ scrollTop, fixed }) => isNumber(scrollTop) && isBoolean(fixed),
[CHANGE_EVENT]: (fixed) => isBoolean(fixed)
};
//#endregion
export { affixEmits, affixProps };
//# sourceMappingURL=affix.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"affix.mjs","names":[],"sources":["../../../../../../packages/components/affix/src/affix.ts"],"sourcesContent":["import {\n buildProps,\n definePropType,\n isBoolean,\n isNumber,\n} from '@element-plus/utils'\nimport { CHANGE_EVENT } from '@element-plus/constants'\nimport { teleportProps } from '@element-plus/components/teleport'\n\nimport type { ExtractPublicPropTypes } from 'vue'\nimport type Affix from './affix.vue'\nimport type { ZIndexType } from '@element-plus/utils'\n\nexport interface AffixProps {\n /**\n * @description affix element zIndex value\n * */\n zIndex?: ZIndexType\n /**\n * @description target container. (CSS selector)\n */\n target?: string\n /**\n * @description offset distance\n * */\n offset?: number\n /**\n * @description position of affix\n * */\n position?: 'top' | 'bottom'\n /**\n * @description whether affix element is teleported, if `true` it will be teleported to where `append-to` sets\n * */\n teleported?: boolean\n /**\n * @description which element the affix element appends to\n * */\n appendTo?: string | HTMLElement\n}\n\n/**\n * @deprecated Removed after 3.0.0, Use `AffixProps` instead.\n */\nexport const affixProps = buildProps({\n /**\n * @description affix element zIndex value\n * */\n zIndex: {\n type: definePropType<ZIndexType>([Number, String]),\n default: 100,\n },\n /**\n * @description target container. (CSS selector)\n */\n target: {\n type: String,\n default: '',\n },\n /**\n * @description offset distance\n * */\n offset: {\n type: Number,\n default: 0,\n },\n /**\n * @description position of affix\n * */\n position: {\n type: String,\n values: ['top', 'bottom'],\n default: 'top',\n },\n /**\n * @description whether affix element is teleported, if `true` it will be teleported to where `append-to` sets\n * */\n teleported: Boolean,\n /**\n * @description which element the affix element appends to\n * */\n appendTo: {\n type: teleportProps.to.type,\n default: 'body',\n },\n} as const)\n\n/**\n * @deprecated Removed after 3.0.0, Use `AffixProps` instead.\n */\nexport type AffixPropsPublic = ExtractPublicPropTypes<typeof affixProps>\n\nexport const affixEmits = {\n scroll: ({ scrollTop, fixed }: { scrollTop: number; fixed: boolean }) =>\n isNumber(scrollTop) && isBoolean(fixed),\n [CHANGE_EVENT]: (fixed: boolean) => isBoolean(fixed),\n}\nexport type AffixEmits = typeof affixEmits\n\nexport type AffixInstance = InstanceType<typeof Affix> & unknown\n"],"mappings":";;;;;;;;;AA2CA,MAAa,aAAa,WAAW;CAInC,QAAQ;EACN,MAAM,eAA2B,CAAC,QAAQ,OAAO,CAAC;EAClD,SAAS;EACV;CAID,QAAQ;EACN,MAAM;EACN,SAAS;EACV;CAID,QAAQ;EACN,MAAM;EACN,SAAS;EACV;CAID,UAAU;EACR,MAAM;EACN,QAAQ,CAAC,OAAO,SAAS;EACzB,SAAS;EACV;CAID,YAAY;CAIZ,UAAU;EACR,MAAM,cAAc,GAAG;EACvB,SAAS;EACV;CACF,CAAU;AAOX,MAAa,aAAa;CACxB,SAAS,EAAE,WAAW,YACpB,SAAS,UAAU,IAAI,UAAU,MAAM;EACxC,gBAAgB,UAAmB,UAAU,MAAM;CACrD"}
@@ -0,0 +1,40 @@
import { AffixProps } from "./affix.js";
import * as vue from "vue";
import * as csstype from "csstype";
//#region ../../packages/components/affix/src/affix.vue.d.ts
declare var __VLS_7: {};
type __VLS_Slots = {} & {
default?: (props: typeof __VLS_7) => any;
};
declare const __VLS_base: vue.DefineComponent<AffixProps, {
/** @description update affix status */update: () => void; /** @description update rootRect info */
updateRoot: () => Promise<void>;
}, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {
scroll: (args_0: {
scrollTop: number;
fixed: boolean;
}) => void;
change: (fixed: boolean) => void;
}, string, vue.PublicProps, Readonly<AffixProps> & Readonly<{
onChange?: ((fixed: boolean) => any) | undefined;
onScroll?: ((args_0: {
scrollTop: number;
fixed: boolean;
}) => any) | undefined;
}>, {
zIndex: csstype.Property.ZIndex;
target: string;
offset: number;
position: "top" | "bottom";
appendTo: string | HTMLElement;
}, {}, {}, {}, string, vue.ComponentProvideOptions, false, {}, any>;
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
declare const _default: typeof __VLS_export;
type __VLS_WithSlots<T, S> = T & {
new (): {
$slots: S;
};
};
//#endregion
export { _default };
@@ -0,0 +1,131 @@
import { CHANGE_EVENT } from "../../../constants/event.mjs";
import { throwError } from "../../../utils/error.mjs";
import { addUnit } from "../../../utils/dom/style.mjs";
import { getScrollContainer } from "../../../utils/dom/scroll.mjs";
import { ElTeleport } from "../../teleport/index.mjs";
import { affixEmits, affixProps } from "./affix.mjs";
import { useNamespace } from "../../../hooks/use-namespace/index.mjs";
import { useElementBounding, useEventListener, useWindowSize } from "@vueuse/core";
import { computed, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onActivated, onDeactivated, onMounted, openBlock, ref, renderSlot, shallowRef, unref, watch, watchEffect, withCtx } from "vue";
//#region ../../packages/components/affix/src/affix.vue?vue&type=script&setup=true&lang.ts
const COMPONENT_NAME = "ElAffix";
var affix_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
name: COMPONENT_NAME,
__name: "affix",
props: affixProps,
emits: affixEmits,
setup(__props, { expose: __expose, emit: __emit }) {
const props = __props;
const emit = __emit;
const ns = useNamespace("affix");
const target = shallowRef();
const root = shallowRef();
const scrollContainer = shallowRef();
const { height: windowHeight } = useWindowSize();
const { height: rootHeight, width: rootWidth, top: rootTop, bottom: rootBottom, left: rootLeft, update: updateRoot } = useElementBounding(root, { windowScroll: false });
const targetRect = useElementBounding(target);
const fixed = ref(false);
const scrollTop = ref(0);
const transform = ref(0);
const teleportDisabled = computed(() => {
return !props.teleported || !fixed.value;
});
const rootStyle = computed(() => {
return {
display: "flow-root",
height: fixed.value ? `${rootHeight.value}px` : "",
width: fixed.value ? `${rootWidth.value}px` : ""
};
});
const affixStyle = computed(() => {
if (!fixed.value) return {};
const offset = addUnit(props.offset);
return {
height: `${rootHeight.value}px`,
width: `${rootWidth.value}px`,
top: props.position === "top" ? offset : "",
bottom: props.position === "bottom" ? offset : "",
left: props.teleported ? `${rootLeft.value}px` : "",
transform: transform.value ? `translateY(${transform.value}px)` : "",
zIndex: props.zIndex
};
});
const update = () => {
if (!scrollContainer.value) return;
scrollTop.value = scrollContainer.value instanceof Window ? document.documentElement.scrollTop : scrollContainer.value.scrollTop || 0;
const { position, target, offset } = props;
const rootHeightOffset = offset + rootHeight.value;
if (position === "top") if (target) {
const difference = targetRect.bottom.value - rootHeightOffset;
fixed.value = offset > rootTop.value && targetRect.bottom.value > 0;
transform.value = difference < 0 ? difference : 0;
} else fixed.value = offset > rootTop.value;
else if (target) {
const difference = windowHeight.value - targetRect.top.value - rootHeightOffset;
fixed.value = windowHeight.value - offset < rootBottom.value && windowHeight.value > targetRect.top.value;
transform.value = difference < 0 ? -difference : 0;
} else fixed.value = windowHeight.value - offset < rootBottom.value;
};
const updateRootRect = async () => {
if (!fixed.value) {
updateRoot();
return;
}
fixed.value = false;
await nextTick();
updateRoot();
fixed.value = true;
};
const handleScroll = async () => {
updateRoot();
await nextTick();
emit("scroll", {
scrollTop: scrollTop.value,
fixed: fixed.value
});
};
watch(fixed, (val) => emit(CHANGE_EVENT, val));
onMounted(() => {
if (props.target) {
target.value = document.querySelector(props.target) ?? void 0;
if (!target.value) throwError(COMPONENT_NAME, `Target does not exist: ${props.target}`);
} else target.value = document.documentElement;
scrollContainer.value = getScrollContainer(root.value, true);
updateRoot();
});
onActivated(() => {
nextTick(updateRootRect);
});
onDeactivated(() => {
fixed.value = false;
});
useEventListener(scrollContainer, "scroll", handleScroll);
watchEffect(update);
__expose({
update,
updateRoot: updateRootRect
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
ref_key: "root",
ref: root,
class: normalizeClass(unref(ns).b()),
style: normalizeStyle(rootStyle.value)
}, [createVNode(unref(ElTeleport), {
disabled: teleportDisabled.value,
to: __props.appendTo
}, {
default: withCtx(() => [createElementVNode("div", {
class: normalizeClass({ [unref(ns).m("fixed")]: fixed.value }),
style: normalizeStyle(affixStyle.value)
}, [renderSlot(_ctx.$slots, "default")], 6)]),
_: 3
}, 8, ["disabled", "to"])], 6);
};
}
});
//#endregion
export { affix_vue_vue_type_script_setup_true_lang_default as default };
//# sourceMappingURL=affix.vue_vue_type_script_setup_true_lang.mjs.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
import affix_vue_vue_type_script_setup_true_lang_default from "./affix.vue_vue_type_script_setup_true_lang.mjs";
//#region ../../packages/components/affix/src/affix.vue
var affix_default = affix_vue_vue_type_script_setup_true_lang_default;
//#endregion
export { affix_default as default };
//# sourceMappingURL=affix2.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"affix2.mjs","names":[],"sources":["../../../../../../packages/components/affix/src/affix.vue"],"sourcesContent":["<template>\n <div ref=\"root\" :class=\"ns.b()\" :style=\"rootStyle\">\n <el-teleport :disabled=\"teleportDisabled\" :to=\"appendTo\">\n <div :class=\"{ [ns.m('fixed')]: fixed }\" :style=\"affixStyle\">\n <slot />\n </div>\n </el-teleport>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport {\n computed,\n nextTick,\n onActivated,\n onDeactivated,\n onMounted,\n ref,\n shallowRef,\n watch,\n watchEffect,\n} from 'vue'\nimport {\n useElementBounding,\n useEventListener,\n useWindowSize,\n} from '@vueuse/core'\nimport ElTeleport from '@element-plus/components/teleport'\nimport { addUnit, getScrollContainer, throwError } from '@element-plus/utils'\nimport { useNamespace } from '@element-plus/hooks'\nimport { CHANGE_EVENT } from '@element-plus/constants'\nimport { affixEmits } from './affix'\n\nimport type { CSSProperties } from 'vue'\nimport type { AffixProps } from './affix'\n\nconst COMPONENT_NAME = 'ElAffix'\ndefineOptions({\n name: COMPONENT_NAME,\n})\nconst props = withDefaults(defineProps<AffixProps>(), {\n zIndex: 100,\n target: '',\n offset: 0,\n position: 'top',\n appendTo: 'body',\n})\nconst emit = defineEmits(affixEmits)\n\nconst ns = useNamespace('affix')\n\nconst target = shallowRef<HTMLElement>()\nconst root = shallowRef<HTMLDivElement>()\nconst scrollContainer = shallowRef<HTMLElement | Window>()\nconst { height: windowHeight } = useWindowSize()\nconst {\n height: rootHeight,\n width: rootWidth,\n top: rootTop,\n bottom: rootBottom,\n left: rootLeft,\n update: updateRoot,\n} = useElementBounding(root, { windowScroll: false })\nconst targetRect = useElementBounding(target)\n\nconst fixed = ref(false)\nconst scrollTop = ref(0)\nconst transform = ref(0)\n\nconst teleportDisabled = computed(() => {\n return !props.teleported || !fixed.value\n})\n\nconst rootStyle = computed<CSSProperties>(() => {\n return {\n display: 'flow-root', // https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Display/Formatting_contexts#explicitly_creating_a_bfc_using_display_flow-root\n height: fixed.value ? `${rootHeight.value}px` : '',\n width: fixed.value ? `${rootWidth.value}px` : '',\n }\n})\n\nconst affixStyle = computed<CSSProperties>(() => {\n if (!fixed.value) return {}\n\n const offset = addUnit(props.offset)\n return {\n height: `${rootHeight.value}px`,\n width: `${rootWidth.value}px`,\n top: props.position === 'top' ? offset : '',\n bottom: props.position === 'bottom' ? offset : '',\n left: props.teleported ? `${rootLeft.value}px` : '',\n transform: transform.value ? `translateY(${transform.value}px)` : '',\n zIndex: props.zIndex,\n }\n})\n\nconst update = () => {\n if (!scrollContainer.value) return\n\n scrollTop.value =\n scrollContainer.value instanceof Window\n ? document.documentElement.scrollTop\n : scrollContainer.value.scrollTop || 0\n\n const { position, target, offset } = props\n const rootHeightOffset = offset + rootHeight.value\n\n if (position === 'top') {\n if (target) {\n const difference = targetRect.bottom.value - rootHeightOffset\n fixed.value = offset > rootTop.value && targetRect.bottom.value > 0\n transform.value = difference < 0 ? difference : 0\n } else {\n fixed.value = offset > rootTop.value\n }\n } else if (target) {\n const difference =\n windowHeight.value - targetRect.top.value - rootHeightOffset\n fixed.value =\n windowHeight.value - offset < rootBottom.value &&\n windowHeight.value > targetRect.top.value\n transform.value = difference < 0 ? -difference : 0\n } else {\n fixed.value = windowHeight.value - offset < rootBottom.value\n }\n}\n\nconst updateRootRect = async () => {\n if (!fixed.value) {\n updateRoot()\n return\n }\n\n fixed.value = false\n await nextTick()\n updateRoot()\n fixed.value = true\n}\n\nconst handleScroll = async () => {\n updateRoot()\n await nextTick()\n emit('scroll', {\n scrollTop: scrollTop.value,\n fixed: fixed.value,\n })\n}\n\nwatch(fixed, (val) => emit(CHANGE_EVENT, val))\n\nonMounted(() => {\n if (props.target) {\n target.value =\n document.querySelector<HTMLElement>(props.target) ?? undefined\n if (!target.value)\n throwError(COMPONENT_NAME, `Target does not exist: ${props.target}`)\n } else {\n target.value = document.documentElement\n }\n scrollContainer.value = getScrollContainer(root.value!, true)\n updateRoot()\n})\n\nonActivated(() => {\n nextTick(updateRootRect)\n})\n\nonDeactivated(() => {\n fixed.value = false\n})\n\nuseEventListener(scrollContainer, 'scroll', handleScroll)\nwatchEffect(update)\n\ndefineExpose({\n /** @description update affix status */\n update,\n /** @description update rootRect info */\n updateRoot: updateRootRect,\n})\n</script>\n"],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
import "../../base/style/css.mjs";
import "element-plus/theme-chalk/el-affix.css";
@@ -0,0 +1,2 @@
import "../../base/style/index.mjs";
import "element-plus/theme-chalk/src/affix.scss";