mirror of
https://github.com/robonen/tools.git
synced 2026-03-20 19:04:46 +00:00
Compare commits
47 Commits
feat/stdli
...
ac4ee586cc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac4ee586cc | ||
| 7dce7ed482 | |||
| df13f0b827 | |||
| 3da393ed08 | |||
| efadb5fe28 | |||
|
|
07e6d3eadc | ||
|
|
6fcc9d5a51 | ||
|
|
289d0d5af1 | ||
| 4bade839e7 | |||
|
|
c4321a2039 | ||
| f6b3bfbca6 | |||
|
|
7541e6aad4 | ||
|
|
a4d9b4c88a | ||
|
|
3b39f64734 | ||
|
|
6ab2d5cebf | ||
|
|
54f1facc4f | ||
|
|
717c41ef88 | ||
|
|
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
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: pnpm
|
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
|
name: Check version changes and publish
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
"url": "git+https://github.com/robonen/tools.git",
|
"url": "git+https://github.com/robonen/tools.git",
|
||||||
"directory": "packages/tsconfig"
|
"directory": "packages/tsconfig"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.13.1",
|
"packageManager": "pnpm@10.29.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.17.1"
|
"node": ">=24.13.1"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"**tsconfig.json"
|
"**tsconfig.json"
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { defineBuildConfig } from 'unbuild';
|
|
||||||
|
|
||||||
export default defineBuildConfig({
|
|
||||||
entries: [
|
|
||||||
'src/browsers',
|
|
||||||
'src/multi',
|
|
||||||
],
|
|
||||||
clean: true,
|
|
||||||
declaration: true,
|
|
||||||
rollup: {
|
|
||||||
emitCJS: true,
|
|
||||||
esbuild: {
|
|
||||||
// minify: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -18,9 +18,9 @@
|
|||||||
"url": "git+https://github.com/robonen/tools.git",
|
"url": "git+https://github.com/robonen/tools.git",
|
||||||
"directory": "packages/platform"
|
"directory": "packages/platform"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.13.1",
|
"packageManager": "pnpm@10.29.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.17.1"
|
"node": ">=24.13.1"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -29,22 +29,22 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
"./browsers": {
|
"./browsers": {
|
||||||
"types": "./dist/browsers.d.ts",
|
"types": "./dist/browsers.d.ts",
|
||||||
"import": "./dist/browsers.mjs",
|
"import": "./dist/browsers.js",
|
||||||
"require": "./dist/browsers.cjs"
|
"require": "./dist/browsers.cjs"
|
||||||
},
|
},
|
||||||
"./multi": {
|
"./multi": {
|
||||||
"types": "./dist/multi.d.ts",
|
"types": "./dist/multi.d.ts",
|
||||||
"import": "./dist/multi.mjs",
|
"import": "./dist/multi.js",
|
||||||
"require": "./dist/multi.cjs"
|
"require": "./dist/multi.cjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"dev": "vitest dev",
|
"dev": "vitest dev",
|
||||||
"build": "unbuild"
|
"build": "tsdown"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@robonen/tsconfig": "workspace:*",
|
"@robonen/tsconfig": "workspace:*",
|
||||||
"unbuild": "catalog:"
|
"tsdown": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
core/platform/tsdown.config.ts
Normal file
12
core/platform/tsdown.config.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { defineConfig } from 'tsdown';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: {
|
||||||
|
browsers: 'src/browsers/index.ts',
|
||||||
|
multi: 'src/multi/index.ts',
|
||||||
|
},
|
||||||
|
format: ['esm', 'cjs'],
|
||||||
|
dts: true,
|
||||||
|
clean: true,
|
||||||
|
hash: false,
|
||||||
|
});
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import { defineBuildConfig } from 'unbuild';
|
|
||||||
|
|
||||||
export default defineBuildConfig({
|
|
||||||
rollup: {
|
|
||||||
esbuild: {
|
|
||||||
// minify: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -18,9 +18,9 @@
|
|||||||
"url": "git+https://github.com/robonen/tools.git",
|
"url": "git+https://github.com/robonen/tools.git",
|
||||||
"directory": "packages/stdlib"
|
"directory": "packages/stdlib"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.13.1",
|
"packageManager": "pnpm@10.29.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.17.1"
|
"node": ">=24.13.1"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -29,18 +29,17 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"import": "./dist/index.mjs",
|
"import": "./dist/index.js",
|
||||||
"require": "./dist/index.cjs"
|
"require": "./dist/index.cjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"dev": "vitest dev",
|
"dev": "vitest dev",
|
||||||
"build": "unbuild"
|
"build": "tsdown"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@robonen/tsconfig": "workspace:*",
|
"@robonen/tsconfig": "workspace:*",
|
||||||
"pathe": "catalog:",
|
"tsdown": "catalog:"
|
||||||
"unbuild": "catalog:"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
core/stdlib/tsdown.config.ts
Normal file
9
core/stdlib/tsdown.config.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'tsdown';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/index.ts'],
|
||||||
|
format: ['esm', 'cjs'],
|
||||||
|
dts: true,
|
||||||
|
clean: true,
|
||||||
|
hash: false,
|
||||||
|
});
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
"url": "git+https://github.com/robonen/tools.git",
|
"url": "git+https://github.com/robonen/tools.git",
|
||||||
"directory": "packages/renovate"
|
"directory": "packages/renovate"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.13.1",
|
"packageManager": "pnpm@10.29.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.17.1"
|
"node": ">=22.22.0"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"default.json"
|
"default.json"
|
||||||
@@ -27,6 +27,6 @@
|
|||||||
"test": "renovate-config-validator ./default.json"
|
"test": "renovate-config-validator ./default.json"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"renovate": "^41.43.5"
|
"renovate": "^43.14.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
package.json
18
package.json
@@ -15,20 +15,20 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/robonen/tools.git"
|
"url": "git+https://github.com/robonen/tools.git"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.13.1",
|
"packageManager": "pnpm@10.29.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.17.1"
|
"node": ">=22.22.0"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.16.5",
|
"@types/node": "^22.19.11",
|
||||||
"citty": "^0.1.6",
|
|
||||||
"jiti": "^2.5.1",
|
|
||||||
"scule": "^1.3.0",
|
|
||||||
"jsdom": "catalog:",
|
|
||||||
"vitest": "catalog:",
|
|
||||||
"@vitest/coverage-v8": "catalog:",
|
"@vitest/coverage-v8": "catalog:",
|
||||||
"@vitest/ui": "catalog:"
|
"@vitest/ui": "catalog:",
|
||||||
|
"citty": "^0.2.1",
|
||||||
|
"jiti": "^2.6.1",
|
||||||
|
"jsdom": "catalog:",
|
||||||
|
"scule": "^1.3.0",
|
||||||
|
"vitest": "catalog:"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "pnpm -r build",
|
"build": "pnpm -r build",
|
||||||
|
|||||||
7163
pnpm-lock.yaml
generated
7163
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,14 @@ packages:
|
|||||||
- core/*
|
- core/*
|
||||||
- infra/*
|
- infra/*
|
||||||
- web/*
|
- web/*
|
||||||
|
- docs
|
||||||
|
|
||||||
catalog:
|
catalog:
|
||||||
'@vitest/coverage-v8': ^3.2.4
|
'@vitest/coverage-v8': ^4.0.18
|
||||||
'@vue/test-utils': ^2.4.6
|
'@vue/test-utils': ^2.4.6
|
||||||
jsdom: ^26.1.0
|
jsdom: ^28.0.0
|
||||||
pathe: ^2.0.3
|
tsdown: ^0.20.3
|
||||||
unbuild: 3.6.0
|
vitest: ^4.0.18
|
||||||
vitest: ^3.2.4
|
'@vitest/ui': ^4.0.18
|
||||||
'@vitest/ui': ^3.2.4
|
vue: ^3.5.28
|
||||||
vue: ^3.5.18
|
nuxt: ^4.3.1
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { defineBuildConfig } from 'unbuild';
|
|
||||||
|
|
||||||
export default defineBuildConfig({
|
|
||||||
externals: ['vue'],
|
|
||||||
rollup: {
|
|
||||||
inlineDependencies: true,
|
|
||||||
esbuild: {
|
|
||||||
// minify: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@robonen/vue",
|
"name": "@robonen/vue",
|
||||||
"version": "0.0.9",
|
"version": "0.0.11",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"description": "Collection of powerful tools for Vue",
|
"description": "Collection of powerful tools for Vue",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
"url": "git+https://github.com/robonen/tools.git",
|
"url": "git+https://github.com/robonen/tools.git",
|
||||||
"directory": "./packages/vue"
|
"directory": "./packages/vue"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.13.1",
|
"packageManager": "pnpm@10.29.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.17.1"
|
"node": ">=24.13.1"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
@@ -27,23 +27,23 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"import": "./dist/index.mjs",
|
"import": "./dist/index.js",
|
||||||
"require": "./dist/index.cjs"
|
"require": "./dist/index.cjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"dev": "vitest dev",
|
"dev": "vitest dev",
|
||||||
"build": "unbuild"
|
"build": "tsdown"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@robonen/platform": "workspace:*",
|
|
||||||
"@robonen/stdlib": "workspace:*",
|
|
||||||
"@robonen/tsconfig": "workspace:*",
|
"@robonen/tsconfig": "workspace:*",
|
||||||
"@vue/test-utils": "catalog:",
|
"@vue/test-utils": "catalog:",
|
||||||
"unbuild": "catalog:"
|
"tsdown": "catalog:"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@robonen/platform": "workspace:*",
|
||||||
|
"@robonen/stdlib": "workspace:*",
|
||||||
"vue": "catalog:"
|
"vue": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from './tryOnBeforeMount';
|
export * from './tryOnBeforeMount';
|
||||||
export * from './tryOnMounted';
|
export * from './tryOnMounted';
|
||||||
export * from './tryOnScopeDispose';
|
export * from './tryOnScopeDispose';
|
||||||
|
export * from './unrefElement';
|
||||||
export * from './useAppSharedState';
|
export * from './useAppSharedState';
|
||||||
export * from './useAsyncState';
|
export * from './useAsyncState';
|
||||||
export * from './useCached';
|
export * from './useCached';
|
||||||
|
|||||||
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 '../..';
|
import { VueToolsError } from '../..';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,8 +34,8 @@ import { VueToolsError } from '../..';
|
|||||||
export function useContextFactory<ContextValue>(name: string) {
|
export function useContextFactory<ContextValue>(name: string) {
|
||||||
const injectionKey: InjectionKey<ContextValue> = Symbol(name);
|
const injectionKey: InjectionKey<ContextValue> = Symbol(name);
|
||||||
|
|
||||||
const injectContext = <Fallback extends ContextValue = ContextValue>(fallback?: Fallback) => {
|
const inject = <Fallback extends ContextValue = ContextValue>(fallback?: Fallback) => {
|
||||||
const context = inject(injectionKey, fallback);
|
const context = vueInject(injectionKey, fallback);
|
||||||
|
|
||||||
if (context !== undefined)
|
if (context !== undefined)
|
||||||
return context;
|
return context;
|
||||||
@@ -43,8 +43,8 @@ export function useContextFactory<ContextValue>(name: string) {
|
|||||||
throw new VueToolsError(`useContextFactory: '${name}' context is not provided`);
|
throw new VueToolsError(`useContextFactory: '${name}' context is not provided`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const provideContext = (context: ContextValue) => {
|
const provide = (context: ContextValue) => {
|
||||||
provide(injectionKey, context);
|
vueProvide(injectionKey, context);
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,8 +54,8 @@ export function useContextFactory<ContextValue>(name: string) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
inject: injectContext,
|
inject,
|
||||||
provide: provideContext,
|
provide,
|
||||||
appProvide,
|
appProvide,
|
||||||
key: injectionKey,
|
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> {
|
export interface useInjectionStoreOptions<Return> {
|
||||||
injectionKey: string | InjectionKey<Return>;
|
injectionName?: string;
|
||||||
defaultValue?: Return;
|
defaultValue?: Return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9,28 +10,28 @@ export interface useInjectionStoreOptions<Return> {
|
|||||||
* @name useInjectionStore
|
* @name useInjectionStore
|
||||||
* @category State
|
* @category State
|
||||||
* @description Create a global state that can be injected into components
|
* @description Create a global state that can be injected into components
|
||||||
*
|
*
|
||||||
* @param {Function} stateFactory A factory function that creates the state
|
* @param {Function} stateFactory A factory function that creates the state
|
||||||
* @param {useInjectionStoreOptions} options An object with the following properties
|
* @param {useInjectionStoreOptions} options An object with the following properties
|
||||||
* @param {string | InjectionKey} options.injectionKey The key to use for the injection
|
* @param {string | InjectionKey} options.injectionKey The key to use for the injection
|
||||||
* @param {any} options.defaultValue The default value to use when the state is not provided
|
* @param {any} options.defaultValue The default value to use when the state is not provided
|
||||||
* @returns {Object} An object with `useProvidingState`, `useAppProvidingState`, and `useInjectedState` functions
|
* @returns {Object} An object with `useProvidingState`, `useAppProvidingState`, and `useInjectedState` functions
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const { useProvidingState, useInjectedState } = useInjectionStore(() => ref('Hello World'));
|
* const { useProvidingState, useInjectedState } = useInjectionStore(() => ref('Hello World'));
|
||||||
*
|
*
|
||||||
* // In a parent component
|
* // In a parent component
|
||||||
* const state = useProvidingState();
|
* const state = useProvidingState();
|
||||||
*
|
*
|
||||||
* // In a child component
|
* // In a child component
|
||||||
* const state = useInjectedState();
|
* const state = useInjectedState();
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const { useProvidingState, useInjectedState } = useInjectionStore(() => ref('Hello World'), {
|
* const { useProvidingState, useInjectedState } = useInjectionStore(() => ref('Hello World'), {
|
||||||
* injectionKey: 'MyState',
|
* injectionKey: 'MyState',
|
||||||
* defaultValue: 'Default Value'
|
* defaultValue: 'Default Value'
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
* // In a plugin
|
* // In a plugin
|
||||||
* {
|
* {
|
||||||
* install(app) {
|
* install(app) {
|
||||||
@@ -38,31 +39,31 @@ export interface useInjectionStoreOptions<Return> {
|
|||||||
* state.value = 'Hello World';
|
* state.value = 'Hello World';
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* // In a component
|
* // In a component
|
||||||
* const state = useInjectedState();
|
* const state = useInjectedState();
|
||||||
*
|
*
|
||||||
* @since 0.0.5
|
* @since 0.0.5
|
||||||
*/
|
*/
|
||||||
export function useInjectionStore<Args extends any[], Return>(
|
export function useInjectionStore<Args extends any[], Return>(
|
||||||
stateFactory: (...args: Args) => 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 useProvidingState = (...args: Args) => {
|
||||||
const state = stateFactory(...args);
|
const state = stateFactory(...args);
|
||||||
provide(key, state);
|
ctx.provide(state);
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useAppProvidingState = (app: App) => (...args: Args) => {
|
const useAppProvidingState = (app: App) => (...args: Args) => {
|
||||||
const state = stateFactory(...args);
|
const state = stateFactory(...args);
|
||||||
app.provide(key, state);
|
ctx.appProvide(app)(state);
|
||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useInjectedState = () => inject(key, options?.defaultValue);
|
const useInjectedState = () => ctx.inject(options?.defaultValue);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
useProvidingState,
|
useProvidingState,
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ describe('useOffsetPagination', () => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(onPageChange).toHaveBeenCalledTimes(1);
|
expect(onPageChange).toHaveBeenCalledTimes(1);
|
||||||
expect(onPageChange).toHaveBeenCalledWith(expect.objectContaining({ currentPage: currentPage.value }));
|
expect(onPageChange.mock.calls[0]![0]).toHaveProperty('currentPage', currentPage.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('call onPageSizeChange callback', async () => {
|
it('call onPageSizeChange callback', async () => {
|
||||||
@@ -81,7 +81,7 @@ describe('useOffsetPagination', () => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(onPageSizeChange).toHaveBeenCalledTimes(1);
|
expect(onPageSizeChange).toHaveBeenCalledTimes(1);
|
||||||
expect(onPageSizeChange).toHaveBeenCalledWith(expect.objectContaining({ currentPageSize: currentPageSize.value }));
|
expect(onPageSizeChange.mock.calls[0]![0]).toHaveProperty('currentPageSize', currentPageSize.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('call onPageCountChange callback', async () => {
|
it('call onPageCountChange callback', async () => {
|
||||||
@@ -93,7 +93,7 @@ describe('useOffsetPagination', () => {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(onTotalPagesChange).toHaveBeenCalledTimes(1);
|
expect(onTotalPagesChange).toHaveBeenCalledTimes(1);
|
||||||
expect(onTotalPagesChange).toHaveBeenCalledWith(expect.objectContaining({ totalPages: totalPages.value }));
|
expect(onTotalPagesChange.mock.calls[0]![0]).toHaveProperty('totalPages', totalPages.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handle complex reactive options', async () => {
|
it('handle complex reactive options', async () => {
|
||||||
|
|||||||
@@ -1,51 +1,39 @@
|
|||||||
import { isRef, ref, toValue, type MaybeRefOrGetter, type MaybeRef, type Ref } from 'vue';
|
import { isRef, ref, toValue, type MaybeRefOrGetter, type MaybeRef, type Ref } from 'vue';
|
||||||
|
|
||||||
// TODO: wip
|
export interface UseToggleOptions<Truthy, Falsy> {
|
||||||
|
truthyValue?: MaybeRefOrGetter<Truthy>,
|
||||||
export interface UseToggleOptions<Enabled, Disabled> {
|
falsyValue?: MaybeRefOrGetter<Falsy>,
|
||||||
enabledValue?: MaybeRefOrGetter<Enabled>,
|
|
||||||
disabledValue?: MaybeRefOrGetter<Disabled>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// two overloads
|
export function useToggle<Truthy = true, Falsy = false>(
|
||||||
// 1. const [state, toggle] = useToggle(nonRefValue, options)
|
initialValue?: MaybeRef<Truthy | Falsy>,
|
||||||
// 2. const toggle = useToggle(refValue, options)
|
options?: UseToggleOptions<Truthy, Falsy>,
|
||||||
// 3. const [state, toggle] = useToggle() // true, false by default
|
): { value: Ref<Truthy | Falsy>, toggle: (value?: Truthy | Falsy) => Truthy | Falsy };
|
||||||
|
|
||||||
export function useToggle<V extends Enabled | Disabled, Enabled = true, Disabled = false>(
|
export function useToggle<Truthy = true, Falsy = false>(
|
||||||
initialValue: Ref<V>,
|
initialValue: MaybeRef<Truthy | Falsy> = false as Truthy | Falsy,
|
||||||
options?: UseToggleOptions<Enabled, Disabled>,
|
options: UseToggleOptions<Truthy, Falsy> = {},
|
||||||
): (value?: V) => V;
|
|
||||||
|
|
||||||
export function useToggle<V extends Enabled | Disabled, Enabled = true, Disabled = false>(
|
|
||||||
initialValue?: V,
|
|
||||||
options?: UseToggleOptions<Enabled, Disabled>,
|
|
||||||
): [Ref<V>, (value?: V) => V];
|
|
||||||
|
|
||||||
export function useToggle<V extends Enabled | Disabled, Enabled = true, Disabled = false>(
|
|
||||||
initialValue: MaybeRef<V> = false,
|
|
||||||
options: UseToggleOptions<Enabled, Disabled> = {},
|
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
enabledValue = false,
|
truthyValue = true as Truthy,
|
||||||
disabledValue = true,
|
falsyValue = false as Falsy,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
const state = ref(initialValue) as Ref<V>;
|
const value = ref(initialValue) as Ref<Truthy | Falsy>;
|
||||||
|
|
||||||
const toggle = (value?: V) => {
|
const toggle = (newValue?: Truthy | Falsy) => {
|
||||||
if (arguments.length) {
|
if (newValue !== undefined) {
|
||||||
state.value = value!;
|
value.value = newValue;
|
||||||
return state.value;
|
return value.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const enabled = toValue(enabledValue);
|
const truthy = toValue(truthyValue);
|
||||||
const disabled = toValue(disabledValue);
|
const falsy = toValue(falsyValue);
|
||||||
|
|
||||||
state.value = state.value === enabled ? disabled : enabled;
|
value.value = value.value === truthy ? falsy : truthy;
|
||||||
|
|
||||||
return state.value;
|
return value.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
return isRef(initialValue) ? toggle : [state, toggle];
|
return { value, toggle };
|
||||||
}
|
}
|
||||||
|
|||||||
11
web/vue/tsdown.config.ts
Normal file
11
web/vue/tsdown.config.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { defineConfig } from 'tsdown';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/index.ts'],
|
||||||
|
format: ['esm', 'cjs'],
|
||||||
|
dts: true,
|
||||||
|
clean: true,
|
||||||
|
hash: false,
|
||||||
|
external: ['vue'],
|
||||||
|
noExternal: [/^@robonen\//],
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user