solid-tiny-utils 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -15,7 +15,7 @@ import { createEventListener } from "./solidjs/create-event-listener.mjs";
15
15
  import { createIntersectionObserver } from "./solidjs/create-intersection-observer.mjs";
16
16
  import { createList } from "./solidjs/create-list.mjs";
17
17
  import { createLoopExec } from "./solidjs/create-loop-exec.mjs";
18
- import { PresenceState, createPresence } from "./solidjs/create-presence.mjs";
18
+ import { MakePresenceOptions, PresencePhase, createPresence } from "./solidjs/create-presence.mjs";
19
19
  import { createThrottle } from "./solidjs/create-throttle.mjs";
20
20
  import { CreateVisibilityObserverOption, EntryCallback, UseVisibilityObserverFn, createVisibilityObserver } from "./solidjs/create-visibility-observer.mjs";
21
21
  import { createWatch } from "./solidjs/create-watch.mjs";
@@ -28,4 +28,4 @@ import { isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, is
28
28
  import { clamp, inRange, max, min, toHex } from "./utils/number.mjs";
29
29
  import { draw, random, shuffle, uid } from "./utils/random.mjs";
30
30
  import { camel, capitalize, dash, pascal, snake, template, title, trim } from "./utils/str.mjs";
31
- export { AnyFn, CreateVisibilityObserverOption, DocumentEventName, EntryCallback, Fn, GeneralEventListener, MaybeAccessor, MaybeArray, MaybeCallableChild, MaybeNullableAccessor, MaybePromise, OKLCH, PresenceState, RGB, UseVisibilityObserverFn, WindowEventName, access, callMaybeCallableChild, camel, capitalize, clamp, clearArray, combineClass, combineStyle, createClickOutside, createDebounce, createDebouncedWatch, createEventListener, createIntersectionObserver, createList, createLoopExec, createPresence, createThrottle, createVisibilityObserver, createWatch, dash, dataIf, draw, hasAnimation, hexToRgb, inRange, isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, isUndefined, isValidHex, isValidOKLCH, isValidRGB, iterate, list, makeEventListener, max, min, mountStyle, noop, oklchToRgb, pascal, random, range, rgbToHex, rgbToOklch, runAtNextAnimationFrame, runSolidEventHandler, shuffle, sleep, snake, stringStyleToObject, template, title, toHex, trim, uid };
31
+ export { AnyFn, CreateVisibilityObserverOption, DocumentEventName, EntryCallback, Fn, GeneralEventListener, MakePresenceOptions, MaybeAccessor, MaybeArray, MaybeCallableChild, MaybeNullableAccessor, MaybePromise, OKLCH, PresencePhase, RGB, UseVisibilityObserverFn, WindowEventName, access, callMaybeCallableChild, camel, capitalize, clamp, clearArray, combineClass, combineStyle, createClickOutside, createDebounce, createDebouncedWatch, createEventListener, createIntersectionObserver, createList, createLoopExec, createPresence, createThrottle, createVisibilityObserver, createWatch, dash, dataIf, draw, hasAnimation, hexToRgb, inRange, isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, isUndefined, isValidHex, isValidOKLCH, isValidRGB, iterate, list, makeEventListener, max, min, mountStyle, noop, oklchToRgb, pascal, random, range, rgbToHex, rgbToOklch, runAtNextAnimationFrame, runSolidEventHandler, shuffle, sleep, snake, stringStyleToObject, template, title, toHex, trim, uid };
@@ -1,11 +1,22 @@
1
1
  import { MaybeAccessor } from "../types/maybe.mjs";
2
+ import "../types/index.mjs";
2
3
  import { Accessor } from "solid-js";
3
4
 
4
5
  //#region src/solidjs/create-presence.d.ts
5
- type PresenceState = "opening" | "opened" | "closing" | "closed";
6
- declare function createPresence(params: {
7
- show: Accessor<boolean>;
8
- element: MaybeAccessor<HTMLElement | undefined>;
9
- }): readonly [Accessor<boolean>, Accessor<PresenceState>];
6
+ interface MakePresenceOptions {
7
+ enterDuration: MaybeAccessor<number>;
8
+ exitDuration: MaybeAccessor<number>;
9
+ initialEnter?: boolean;
10
+ }
11
+ type PresencePhase = "idle" | "pre-enter" | "entering" | "entered" | "exiting" | "exited";
12
+ declare function createPresence<TItem>(item: Accessor<TItem | undefined>, options: MakePresenceOptions): {
13
+ isMounted: () => boolean;
14
+ mountedItem: Accessor<TItem | undefined>;
15
+ isVisible: Accessor<boolean>;
16
+ isAnimating: Accessor<boolean>;
17
+ isEntering: Accessor<boolean>;
18
+ isExiting: Accessor<boolean>;
19
+ phase: Accessor<PresencePhase>;
20
+ };
10
21
  //#endregion
11
- export { PresenceState, createPresence };
22
+ export { MakePresenceOptions, PresencePhase, createPresence };
@@ -1,28 +1,88 @@
1
+ import { isDefined } from "../utils/is.mjs";
2
+ import { runAtNextAnimationFrame } from "../utils/async.mjs";
1
3
  import { noop } from "../utils/constant.mjs";
2
- import { hasAnimation } from "../dom/animation.mjs";
3
- import { makeEventListener } from "./make-event-listener.mjs";
4
4
  import { access } from "./utils.mjs";
5
5
  import { createWatch } from "./create-watch.mjs";
6
- import { createMemo, createSignal } from "solid-js";
6
+ import { createEffect, createMemo, createSignal, onCleanup, untrack } from "solid-js";
7
7
 
8
8
  //#region src/solidjs/create-presence.ts
9
- function createPresence(params) {
10
- const [state, setState] = createSignal(access(params.show) ? "opened" : "closed");
11
- createWatch(createMemo(() => access(params.show)), (show) => {
12
- if (show) setState("opening");
13
- else setState("closing");
14
- }, { defer: true });
9
+ function makeTimeout(ms, fn) {
10
+ if (ms() <= 0) {
11
+ fn();
12
+ return noop;
13
+ }
14
+ const timeoutId = setTimeout(() => {
15
+ fn();
16
+ }, ms());
17
+ return () => clearTimeout(timeoutId);
18
+ }
19
+ /**
20
+ * Animates the appearance of its children.
21
+ *
22
+ * @internal - to be combined with `createPresence` in the future
23
+ */
24
+ function createPresenceBase(source, options) {
25
+ const enterDuration = () => access(options.enterDuration);
26
+ const exitDuration = () => access(options.exitDuration);
27
+ const initialSource = untrack(source);
28
+ let initialPhase = "idle";
29
+ if (initialSource) initialPhase = options.initialEnter ? "pre-enter" : "entered";
30
+ const [phase, setPhase] = createSignal(initialPhase);
15
31
  let clear = noop;
16
- createWatch(state, (current) => {
32
+ onCleanup(clear);
33
+ createWatch(source, (visible) => {
34
+ setPhase((prev) => {
35
+ if (visible) {
36
+ if (prev === "idle" || prev === "exited") return "pre-enter";
37
+ return prev;
38
+ }
39
+ if (prev === "entered" || prev === "entering") return "exiting";
40
+ return prev;
41
+ });
42
+ });
43
+ createWatch(phase, (currentPhase) => {
17
44
  clear();
18
- const el = access(params.element);
19
- if (!el) return;
20
- if (current.endsWith("ing")) if (hasAnimation(el)) clear = makeEventListener(el, "animationend", () => {
21
- setState(current === "opening" ? "opened" : "closed");
45
+ if (currentPhase === "pre-enter") runAtNextAnimationFrame(() => {
46
+ setPhase("entering");
22
47
  });
23
- else setState(current === "opening" ? "opened" : "closed");
48
+ if (currentPhase === "entering") clear = makeTimeout(enterDuration, () => setPhase("entered"));
49
+ if (currentPhase === "exiting") clear = makeTimeout(exitDuration, () => setPhase("exited"));
50
+ if (currentPhase === "exited") setPhase("idle");
51
+ });
52
+ const isVisible = createMemo(() => ["entering", "entered"].includes(phase()));
53
+ const isMounted = createMemo(() => phase() !== "idle");
54
+ const isExiting = createMemo(() => phase() === "exiting");
55
+ const isEntering = createMemo(() => phase() === "entering");
56
+ return {
57
+ isMounted,
58
+ isVisible,
59
+ isAnimating: createMemo(() => isEntering() || isExiting()),
60
+ isEntering,
61
+ isExiting,
62
+ phase
63
+ };
64
+ }
65
+ const itemShouldBeMounted = (item) => item !== false && item != null;
66
+ function createPresence(item, options) {
67
+ const initial = untrack(item);
68
+ const [mountedItem, setMountedItem] = createSignal(initial);
69
+ const [shouldBeMounted, setShouldBeMounted] = createSignal(itemShouldBeMounted(initial));
70
+ const { isMounted, ...rest } = createPresenceBase(shouldBeMounted, options);
71
+ createEffect(() => {
72
+ if (mountedItem() !== item()) {
73
+ if (isMounted()) setShouldBeMounted(false);
74
+ else if (itemShouldBeMounted(item())) {
75
+ setMountedItem(() => item());
76
+ setShouldBeMounted(true);
77
+ }
78
+ } else if (!itemShouldBeMounted(item())) setShouldBeMounted(false);
79
+ else if (itemShouldBeMounted(item())) setShouldBeMounted(true);
24
80
  });
25
- return [createMemo(() => state() !== "closed"), state];
81
+ return {
82
+ ...rest,
83
+ isMounted: () => isMounted() && isDefined(mountedItem()),
84
+ mountedItem
85
+ };
26
86
  }
27
87
 
28
88
  //#endregion
@@ -6,7 +6,7 @@ import { createEventListener } from "./create-event-listener.mjs";
6
6
  import { createIntersectionObserver } from "./create-intersection-observer.mjs";
7
7
  import { createList } from "./create-list.mjs";
8
8
  import { createLoopExec } from "./create-loop-exec.mjs";
9
- import { PresenceState, createPresence } from "./create-presence.mjs";
9
+ import { MakePresenceOptions, PresencePhase, createPresence } from "./create-presence.mjs";
10
10
  import { createThrottle } from "./create-throttle.mjs";
11
11
  import { CreateVisibilityObserverOption, EntryCallback, UseVisibilityObserverFn, createVisibilityObserver } from "./create-visibility-observer.mjs";
12
12
  import { createWatch } from "./create-watch.mjs";
@@ -1,12 +1,19 @@
1
- import { isFn } from "../utils/is.mjs";
1
+ import { isArray, isFn } from "../utils/is.mjs";
2
2
 
3
3
  //#region src/solidjs/utils.ts
4
4
  function access(value) {
5
5
  return isFn(value) ? value() : value;
6
6
  }
7
7
  function runSolidEventHandler(event, handler) {
8
- if (typeof handler === "function") handler(event);
9
- if (Array.isArray(handler)) handler[0](handler[1], event);
8
+ if (isFn(handler)) {
9
+ handler(event);
10
+ return;
11
+ }
12
+ if (isArray(handler)) {
13
+ const h = handler[0];
14
+ const data = handler[1];
15
+ h(data, event);
16
+ }
10
17
  }
11
18
  function callMaybeCallableChild(children, ...args) {
12
19
  return isFn(children) ? children(...args) : children;
package/package.json CHANGED
@@ -1,8 +1,17 @@
1
1
  {
2
2
  "name": "solid-tiny-utils",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "A collection of tiny utilities for SolidJS applications",
5
- "main": "./dist/index.mjs",
5
+ "author": "solid tiny",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/solid-tiny/solid-tiny-utils#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/solid-tiny/solid-tiny-utils.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/solid-tiny/solid-tiny-utils/issues"
14
+ },
6
15
  "type": "module",
7
16
  "files": [
8
17
  "dist"
@@ -12,7 +21,7 @@
12
21
  "solid-js": "^1.9.7"
13
22
  },
14
23
  "devDependencies": {
15
- "@biomejs/biome": "2.3.10",
24
+ "@biomejs/biome": "2.3.11",
16
25
  "@formkit/auto-animate": "^0.9.0",
17
26
  "@solidjs/router": "^0.15.4",
18
27
  "@solidjs/testing-library": "^0.8.10",
@@ -20,14 +29,14 @@
20
29
  "@testing-library/user-event": "^14.6.1",
21
30
  "@types/culori": "^4.0.0",
22
31
  "@types/node": "^25.0.3",
23
- "@typescript/native-preview": "7.0.0-dev.20260102.1",
32
+ "@typescript/native-preview": "7.0.0-dev.20260114.1",
24
33
  "@vitest/ui": "^4.0.16",
25
34
  "bumpp": "^10.3.2",
26
35
  "culori": "^4.0.2",
27
36
  "jsdom": "^27.3.0",
28
37
  "solid-tiny-context": "0.2.3",
29
- "tsdown": "^0.18.4",
30
- "ultracite": "7.0.5",
38
+ "tsdown": "^0.19.0",
39
+ "ultracite": "7.0.11",
31
40
  "unocss": "^66.3.3",
32
41
  "vite": "^7.3.0",
33
42
  "vite-plugin-solid": "^2.11.10",
@@ -41,9 +50,6 @@
41
50
  "typescript",
42
51
  "utils"
43
52
  ],
44
- "author": "",
45
- "license": "MIT",
46
- "module": "./dist/index.mjs",
47
53
  "types": "./dist/index.d.mts",
48
54
  "exports": {
49
55
  ".": "./dist/index.mjs",
@@ -55,9 +61,9 @@
55
61
  "test": "vitest --run",
56
62
  "clean": "rimraf dist node_modules pnpm-lock.yaml",
57
63
  "test:ui": "vitest --ui",
58
- "lint": "pnpm dlx ultracite@latest check",
59
- "lint:error": "pnpm dlx ultracite@latest check --diagnostic-level error",
60
- "lint:fix": "pnpm dlx ultracite@latest fix",
64
+ "lint": "pnpm ultracite check",
65
+ "lint:error": "pnpm ultracite check --diagnostic-level error",
66
+ "lint:fix": "pnpm ultracite fix",
61
67
  "type-check": "tsgo --noEmit --skipLibCheck",
62
68
  "bump": "pnpm type-check && pnpm test && pnpm bumpp --no-push",
63
69
  "prepublish": "pnpm build"