mirror of
https://github.com/robonen/tools.git
synced 2026-03-20 19:04:46 +00:00
Compare commits
31 Commits
feat/stdli
...
a4158609c1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4158609c1 | ||
|
|
3747f5213e | ||
| daf18871a0 | |||
|
|
8bf9943e9e | ||
|
|
0e67715d9e | ||
|
|
3e43e4db3d | ||
| b8308e383c | |||
|
|
93c878cc35 | ||
| 7653975fa4 | |||
|
|
e2cb3f5a75 | ||
|
|
67fbad8930 | ||
|
|
e49c49e320 | ||
|
|
43cdc3b5e6 | ||
| a9a6c04176 | |||
| a6d3e8971f | |||
| 40dfdabd08 | |||
|
|
876a815fd3 | ||
| b1b9889ad2 | |||
|
|
9d2a393372 | ||
|
|
4071e49ad6 | ||
| 88bd87f9b0 | |||
|
|
ac265c05a8 | ||
| 69e5ebc085 | |||
| 48a85dbae2 | |||
| 0cfdce7456 | |||
| e035d1abca | |||
| 1851d5c80c | |||
| 48626a9fe5 | |||
| 04aa9e4721 | |||
| d55e3989f3 | |||
|
|
acee7e4167 |
4
.github/workflows/ci.yaml
vendored
4
.github/workflows/ci.yaml
vendored
@@ -16,14 +16,14 @@ jobs:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: pnpm
|
||||
|
||||
4
.github/workflows/publish.yaml
vendored
4
.github/workflows/publish.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Check version changes and publish
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: pnpm
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
"url": "git+https://github.com/robonen/tools.git",
|
||||
"directory": "packages/tsconfig"
|
||||
},
|
||||
"packageManager": "pnpm@10.13.1",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"engines": {
|
||||
"node": ">=22.17.1"
|
||||
"node": ">=24.11.1"
|
||||
},
|
||||
"files": [
|
||||
"**tsconfig.json"
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
"url": "git+https://github.com/robonen/tools.git",
|
||||
"directory": "packages/platform"
|
||||
},
|
||||
"packageManager": "pnpm@10.13.1",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"engines": {
|
||||
"node": ">=22.17.1"
|
||||
"node": ">=24.11.1"
|
||||
},
|
||||
"type": "module",
|
||||
"files": [
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
"url": "git+https://github.com/robonen/tools.git",
|
||||
"directory": "packages/stdlib"
|
||||
},
|
||||
"packageManager": "pnpm@10.13.1",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"engines": {
|
||||
"node": ">=22.17.1"
|
||||
"node": ">=24.11.1"
|
||||
},
|
||||
"type": "module",
|
||||
"files": [
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
"url": "git+https://github.com/robonen/tools.git",
|
||||
"directory": "packages/renovate"
|
||||
},
|
||||
"packageManager": "pnpm@10.13.1",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"engines": {
|
||||
"node": ">=22.17.1"
|
||||
"node": ">=24.11.1"
|
||||
},
|
||||
"files": [
|
||||
"default.json"
|
||||
@@ -27,6 +27,6 @@
|
||||
"test": "renovate-config-validator ./default.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"renovate": "^41.43.5"
|
||||
"renovate": "^42.26.2"
|
||||
}
|
||||
}
|
||||
|
||||
18
package.json
18
package.json
@@ -15,20 +15,20 @@
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/robonen/tools.git"
|
||||
},
|
||||
"packageManager": "pnpm@10.13.1",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"engines": {
|
||||
"node": ">=22.17.1"
|
||||
"node": ">=24.11.1"
|
||||
},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.16.5",
|
||||
"citty": "^0.1.6",
|
||||
"jiti": "^2.5.1",
|
||||
"scule": "^1.3.0",
|
||||
"jsdom": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"@types/node": "^24.10.1",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"@vitest/ui": "catalog:"
|
||||
"@vitest/ui": "catalog:",
|
||||
"citty": "^0.1.6",
|
||||
"jiti": "^2.6.1",
|
||||
"jsdom": "catalog:",
|
||||
"scule": "^1.3.0",
|
||||
"vitest": "catalog:"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm -r build",
|
||||
|
||||
4287
pnpm-lock.yaml
generated
4287
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,9 @@ packages:
|
||||
catalog:
|
||||
'@vitest/coverage-v8': ^3.2.4
|
||||
'@vue/test-utils': ^2.4.6
|
||||
jsdom: ^26.1.0
|
||||
jsdom: ^27.2.0
|
||||
pathe: ^2.0.3
|
||||
unbuild: 3.6.0
|
||||
unbuild: 3.6.1
|
||||
vitest: ^3.2.4
|
||||
'@vitest/ui': ^3.2.4
|
||||
vue: ^3.5.18
|
||||
vue: ^3.5.24
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@robonen/vue",
|
||||
"version": "0.0.9",
|
||||
"version": "0.0.11",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Collection of powerful tools for Vue",
|
||||
"keywords": [
|
||||
@@ -16,9 +16,9 @@
|
||||
"url": "git+https://github.com/robonen/tools.git",
|
||||
"directory": "./packages/vue"
|
||||
},
|
||||
"packageManager": "pnpm@10.13.1",
|
||||
"packageManager": "pnpm@10.22.0",
|
||||
"engines": {
|
||||
"node": ">=22.17.1"
|
||||
"node": ">=24.11.1"
|
||||
},
|
||||
"type": "module",
|
||||
"files": [
|
||||
@@ -37,13 +37,13 @@
|
||||
"build": "unbuild"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@robonen/platform": "workspace:*",
|
||||
"@robonen/stdlib": "workspace:*",
|
||||
"@robonen/tsconfig": "workspace:*",
|
||||
"@vue/test-utils": "catalog:",
|
||||
"unbuild": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@robonen/platform": "workspace:*",
|
||||
"@robonen/stdlib": "workspace:*",
|
||||
"vue": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
61
web/vue/src/composables/unrefElement/index.test.ts
Normal file
61
web/vue/src/composables/unrefElement/index.test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { computed, defineComponent, nextTick, ref, shallowRef } from 'vue';
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { unrefElement } from '.';
|
||||
|
||||
describe('unrefElement', () => {
|
||||
it('returns a plain element when passed a raw element', () => {
|
||||
const htmlEl = document.createElement('div');
|
||||
const svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
|
||||
expect(unrefElement(htmlEl)).toBe(htmlEl);
|
||||
expect(unrefElement(svgEl)).toBe(svgEl);
|
||||
});
|
||||
|
||||
it('returns element when passed a ref or shallowRef to an element', () => {
|
||||
const el = document.createElement('div');
|
||||
const elRef = ref<HTMLElement | null>(el);
|
||||
const shallowElRef = shallowRef<HTMLElement | null>(el);
|
||||
|
||||
expect(unrefElement(elRef)).toBe(el);
|
||||
expect(unrefElement(shallowElRef)).toBe(el);
|
||||
});
|
||||
|
||||
it('returns element when passed a computed ref or getter function', () => {
|
||||
const el = document.createElement('div');
|
||||
const computedElRef = computed(() => el);
|
||||
const elGetter = () => el;
|
||||
|
||||
expect(unrefElement(computedElRef)).toBe(el);
|
||||
expect(unrefElement(elGetter)).toBe(el);
|
||||
});
|
||||
|
||||
it('returns component $el when passed a component instance', async () => {
|
||||
const Child = defineComponent({
|
||||
template: `<span class="child-el">child</span>`,
|
||||
});
|
||||
|
||||
const Parent = defineComponent({
|
||||
components: { Child },
|
||||
template: `<Child ref="childRef" />`,
|
||||
});
|
||||
|
||||
const wrapper = mount(Parent);
|
||||
await nextTick();
|
||||
|
||||
const childInstance = (wrapper.vm as any).$refs.childRef;
|
||||
const result = unrefElement(childInstance);
|
||||
|
||||
expect(result).toBe(childInstance.$el);
|
||||
expect((result as HTMLElement).classList.contains('child-el')).toBe(true);
|
||||
});
|
||||
|
||||
it('handles null and undefined values', () => {
|
||||
expect(unrefElement(undefined)).toBe(undefined);
|
||||
expect(unrefElement(null)).toBe(null);
|
||||
expect(unrefElement(ref(null))).toBe(null);
|
||||
expect(unrefElement(ref(undefined))).toBe(undefined);
|
||||
expect(unrefElement(() => null)).toBe(null);
|
||||
expect(unrefElement(() => undefined)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
33
web/vue/src/composables/unrefElement/index.ts
Normal file
33
web/vue/src/composables/unrefElement/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { ComponentPublicInstance, MaybeRef, MaybeRefOrGetter } from 'vue';
|
||||
import { toValue } from 'vue';
|
||||
|
||||
export type VueInstance = ComponentPublicInstance;
|
||||
export type MaybeElement = HTMLElement | SVGElement | VueInstance | undefined | null;
|
||||
|
||||
export type MaybeElementRef<El extends MaybeElement = MaybeElement> = MaybeRef<El>;
|
||||
export type MaybeComputedElementRef<El extends MaybeElement = MaybeElement> = MaybeRefOrGetter<El>;
|
||||
|
||||
export type UnRefElementReturn<T extends MaybeElement = MaybeElement> = T extends VueInstance ? Exclude<MaybeElement, VueInstance> : T | undefined;
|
||||
|
||||
/**
|
||||
* @name unrefElement
|
||||
* @category Components
|
||||
* @description Unwraps a Vue element reference to get the underlying instance or DOM element.
|
||||
*
|
||||
* @param {MaybeComputedElementRef<El>} elRef - The element reference to unwrap.
|
||||
* @returns {UnRefElementReturn<El>} - The unwrapped element or undefined.
|
||||
*
|
||||
* @example
|
||||
* const element = useTemplateRef<HTMLElement>('element');
|
||||
* const result = unrefElement(element); // result is the element instance
|
||||
*
|
||||
* @example
|
||||
* const component = useTemplateRef<Component>('component');
|
||||
* const result = unrefElement(component); // result is the component instance
|
||||
*
|
||||
* @since 0.0.11
|
||||
*/
|
||||
export function unrefElement<El extends MaybeElement>(elRef: MaybeComputedElementRef<El>): UnRefElementReturn<El> {
|
||||
const plain = toValue(elRef);
|
||||
return (plain as VueInstance)?.$el ?? plain;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { inject, provide, type InjectionKey, type App } from 'vue';
|
||||
import { inject as vueInject, provide as vueProvide, type InjectionKey, type App } from 'vue';
|
||||
import { VueToolsError } from '../..';
|
||||
|
||||
/**
|
||||
@@ -34,8 +34,8 @@ import { VueToolsError } from '../..';
|
||||
export function useContextFactory<ContextValue>(name: string) {
|
||||
const injectionKey: InjectionKey<ContextValue> = Symbol(name);
|
||||
|
||||
const injectContext = <Fallback extends ContextValue = ContextValue>(fallback?: Fallback) => {
|
||||
const context = inject(injectionKey, fallback);
|
||||
const inject = <Fallback extends ContextValue = ContextValue>(fallback?: Fallback) => {
|
||||
const context = vueInject(injectionKey, fallback);
|
||||
|
||||
if (context !== undefined)
|
||||
return context;
|
||||
@@ -43,8 +43,8 @@ export function useContextFactory<ContextValue>(name: string) {
|
||||
throw new VueToolsError(`useContextFactory: '${name}' context is not provided`);
|
||||
};
|
||||
|
||||
const provideContext = (context: ContextValue) => {
|
||||
provide(injectionKey, context);
|
||||
const provide = (context: ContextValue) => {
|
||||
vueProvide(injectionKey, context);
|
||||
return context;
|
||||
};
|
||||
|
||||
@@ -54,8 +54,8 @@ export function useContextFactory<ContextValue>(name: string) {
|
||||
};
|
||||
|
||||
return {
|
||||
inject: injectContext,
|
||||
provide: provideContext,
|
||||
inject,
|
||||
provide,
|
||||
appProvide,
|
||||
key: injectionKey,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { inject, provide, type App, type InjectionKey } from 'vue';
|
||||
import { useContextFactory } from '../useContextFactory';
|
||||
import type { App, InjectionKey } from 'vue';
|
||||
|
||||
export interface useInjectionStoreOptions<Return> {
|
||||
injectionKey: string | InjectionKey<Return>;
|
||||
injectionName?: string;
|
||||
defaultValue?: Return;
|
||||
}
|
||||
|
||||
@@ -46,23 +47,23 @@ export interface useInjectionStoreOptions<Return> {
|
||||
*/
|
||||
export function useInjectionStore<Args extends any[], Return>(
|
||||
stateFactory: (...args: Args) => Return,
|
||||
options?: useInjectionStoreOptions<Return>,
|
||||
options?: useInjectionStoreOptions<Return>
|
||||
) {
|
||||
const key = options?.injectionKey ?? Symbol(stateFactory.name ?? 'InjectionStore');
|
||||
const ctx = useContextFactory<Return>(options?.injectionName ?? stateFactory.name ?? 'InjectionStore');
|
||||
|
||||
const useProvidingState = (...args: Args) => {
|
||||
const state = stateFactory(...args);
|
||||
provide(key, state);
|
||||
ctx.provide(state);
|
||||
return state;
|
||||
};
|
||||
|
||||
const useAppProvidingState = (app: App) => (...args: Args) => {
|
||||
const state = stateFactory(...args);
|
||||
app.provide(key, state);
|
||||
ctx.appProvide(app)(state);
|
||||
return state;
|
||||
};
|
||||
|
||||
const useInjectedState = () => inject(key, options?.defaultValue);
|
||||
const useInjectedState = () => ctx.inject(options?.defaultValue);
|
||||
|
||||
return {
|
||||
useProvidingState,
|
||||
|
||||
Reference in New Issue
Block a user