@intentface/ui 0.0.0 → 0.7.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/LICENSE +21 -0
- package/README.md +145 -2
- package/dist/ask-user/ask-user.d.ts +104 -0
- package/dist/ask-user/ask-user.js +245 -0
- package/dist/ask-user/index.d.ts +3 -0
- package/dist/ask-user/index.js +3 -0
- package/dist/ask-user/index.parts.d.ts +1 -0
- package/dist/ask-user/index.parts.js +5 -0
- package/dist/attachments/attachments.d.ts +73 -0
- package/dist/attachments/attachments.js +121 -0
- package/dist/attachments/index.d.ts +3 -0
- package/dist/attachments/index.js +3 -0
- package/dist/attachments/index.parts.d.ts +1 -0
- package/dist/attachments/index.parts.js +5 -0
- package/dist/chip/chip.d.ts +45 -0
- package/dist/chip/chip.js +43 -0
- package/dist/chip/index.d.ts +2 -0
- package/dist/chip/index.js +2 -0
- package/dist/chip/index.parts.d.ts +1 -0
- package/dist/chip/index.parts.js +5 -0
- package/dist/chip-markdown.d.ts +25 -0
- package/dist/chip-markdown.js +54 -0
- package/dist/composer/actions.d.ts +35 -0
- package/dist/composer/actions.js +76 -0
- package/dist/composer/ask-user-machine.d.ts +52 -0
- package/dist/composer/ask-user-machine.js +164 -0
- package/dist/composer/attachments-machine.d.ts +34 -0
- package/dist/composer/attachments-machine.js +91 -0
- package/dist/composer/attachments.d.ts +16 -0
- package/dist/composer/attachments.js +32 -0
- package/dist/composer/command-list.d.ts +49 -0
- package/dist/composer/command-list.js +360 -0
- package/dist/composer/commands.d.ts +28 -0
- package/dist/composer/commands.js +56 -0
- package/dist/composer/container.d.ts +3 -0
- package/dist/composer/container.js +32 -0
- package/dist/composer/controller.d.ts +3 -0
- package/dist/composer/controller.js +6 -0
- package/dist/composer/editor-dom.d.ts +57 -0
- package/dist/composer/editor-dom.js +517 -0
- package/dist/composer/fuzzy.d.ts +4 -0
- package/dist/composer/fuzzy.js +49 -0
- package/dist/composer/index.d.ts +25 -0
- package/dist/composer/index.js +13 -0
- package/dist/composer/index.parts.d.ts +11 -0
- package/dist/composer/index.parts.js +15 -0
- package/dist/composer/internals.d.ts +30 -0
- package/dist/composer/internals.js +102 -0
- package/dist/composer/keyboard.d.ts +61 -0
- package/dist/composer/keyboard.js +75 -0
- package/dist/composer/panel.d.ts +28 -0
- package/dist/composer/panel.js +76 -0
- package/dist/composer/placeholder.d.ts +10 -0
- package/dist/composer/placeholder.js +8 -0
- package/dist/composer/popover.d.ts +12 -0
- package/dist/composer/popover.js +62 -0
- package/dist/composer/prefix-detection.d.ts +23 -0
- package/dist/composer/prefix-detection.js +67 -0
- package/dist/composer/root.d.ts +21 -0
- package/dist/composer/root.js +124 -0
- package/dist/composer/segments.d.ts +108 -0
- package/dist/composer/segments.js +366 -0
- package/dist/composer/store.d.ts +98 -0
- package/dist/composer/store.js +457 -0
- package/dist/composer/textarea.d.ts +39 -0
- package/dist/composer/textarea.js +64 -0
- package/dist/composer/trigger-tracker.d.ts +12 -0
- package/dist/composer/trigger-tracker.js +90 -0
- package/dist/composer/types.d.ts +127 -0
- package/dist/composer/types.js +4 -0
- package/dist/composer/use-composer-editor.d.ts +43 -0
- package/dist/composer/use-composer-editor.js +653 -0
- package/dist/generative/catalog.d.ts +177 -0
- package/dist/generative/catalog.js +20 -0
- package/dist/generative/index.d.ts +26 -0
- package/dist/generative/index.js +20 -0
- package/dist/generative/json-schema.d.ts +45 -0
- package/dist/generative/json-schema.js +216 -0
- package/dist/generative/markdown.d.ts +21 -0
- package/dist/generative/markdown.js +76 -0
- package/dist/generative/tree.d.ts +56 -0
- package/dist/generative/tree.js +365 -0
- package/dist/generative/use-tree.d.ts +12 -0
- package/dist/generative/use-tree.js +64 -0
- package/dist/internal/change-event-details.d.ts +12 -0
- package/dist/internal/change-event-details.js +16 -0
- package/dist/internal/collapsible.d.ts +22 -0
- package/dist/internal/collapsible.js +94 -0
- package/dist/internal/collection.d.ts +32 -0
- package/dist/internal/collection.js +72 -0
- package/dist/internal/iso-layout-effect.d.ts +2 -0
- package/dist/internal/iso-layout-effect.js +6 -0
- package/dist/internal/portal.d.ts +6 -0
- package/dist/internal/portal.js +18 -0
- package/dist/internal/primitive-props.d.ts +4 -0
- package/dist/internal/primitive-props.js +3 -0
- package/dist/internal/render/baseTypes.d.ts +18 -0
- package/dist/internal/render/baseTypes.js +4 -0
- package/dist/internal/render/empty.d.ts +3 -0
- package/dist/internal/render/empty.js +5 -0
- package/dist/internal/render/getReactElementRef.d.ts +5 -0
- package/dist/internal/render/getReactElementRef.js +15 -0
- package/dist/internal/render/getStateAttributesProps.d.ts +4 -0
- package/dist/internal/render/getStateAttributesProps.js +23 -0
- package/dist/internal/render/mergeObjects.d.ts +1 -0
- package/dist/internal/render/mergeObjects.js +14 -0
- package/dist/internal/render/mergeProps.d.ts +55 -0
- package/dist/internal/render/mergeProps.js +183 -0
- package/dist/internal/render/positioning.d.ts +33 -0
- package/dist/internal/render/positioning.js +112 -0
- package/dist/internal/render/reactVersion.d.ts +3 -0
- package/dist/internal/render/reactVersion.js +7 -0
- package/dist/internal/render/resolveClassName.d.ts +8 -0
- package/dist/internal/render/resolveClassName.js +12 -0
- package/dist/internal/render/resolveStyle.d.ts +8 -0
- package/dist/internal/render/resolveStyle.js +12 -0
- package/dist/internal/render/transition.d.ts +47 -0
- package/dist/internal/render/transition.js +259 -0
- package/dist/internal/render/types.d.ts +74 -0
- package/dist/internal/render/types.js +3 -0
- package/dist/internal/render/useMergedRefs.d.ts +21 -0
- package/dist/internal/render/useMergedRefs.js +102 -0
- package/dist/internal/render/useRefWithInit.d.ts +10 -0
- package/dist/internal/render/useRefWithInit.js +12 -0
- package/dist/internal/render/useRender.d.ts +71 -0
- package/dist/internal/render/useRender.js +12 -0
- package/dist/internal/render/useRenderElement.d.ts +62 -0
- package/dist/internal/render/useRenderElement.js +157 -0
- package/dist/internal/render/warn.d.ts +1 -0
- package/dist/internal/render/warn.js +15 -0
- package/dist/internal/safe-polygon.d.ts +21 -0
- package/dist/internal/safe-polygon.js +179 -0
- package/dist/internal/scroll-into-view-within.d.ts +1 -0
- package/dist/internal/scroll-into-view-within.js +26 -0
- package/dist/internal/standard-schema.d.ts +38 -0
- package/dist/internal/standard-schema.js +4 -0
- package/dist/internal/state-mappings.d.ts +8 -0
- package/dist/internal/state-mappings.js +17 -0
- package/dist/internal/use-controlled.d.ts +19 -0
- package/dist/internal/use-controlled.js +33 -0
- package/dist/message/index.d.ts +3 -0
- package/dist/message/index.js +3 -0
- package/dist/message/index.parts.d.ts +1 -0
- package/dist/message/index.parts.js +5 -0
- package/dist/message/message.d.ts +58 -0
- package/dist/message/message.js +93 -0
- package/dist/message-utils.d.ts +55 -0
- package/dist/message-utils.js +79 -0
- package/dist/nav/index.d.ts +4 -0
- package/dist/nav/index.js +5 -0
- package/dist/nav/index.parts.d.ts +3 -0
- package/dist/nav/index.parts.js +7 -0
- package/dist/nav/nav.d.ts +152 -0
- package/dist/nav/nav.js +660 -0
- package/dist/nav/store.d.ts +50 -0
- package/dist/nav/store.js +95 -0
- package/dist/reasoning/index.d.ts +3 -0
- package/dist/reasoning/index.js +3 -0
- package/dist/reasoning/index.parts.d.ts +1 -0
- package/dist/reasoning/index.parts.js +5 -0
- package/dist/reasoning/reasoning.d.ts +38 -0
- package/dist/reasoning/reasoning.js +67 -0
- package/dist/shell/index.d.ts +5 -0
- package/dist/shell/index.js +5 -0
- package/dist/shell/index.parts.d.ts +3 -0
- package/dist/shell/index.parts.js +7 -0
- package/dist/shell/shell.d.ts +108 -0
- package/dist/shell/shell.js +390 -0
- package/dist/shell/store.d.ts +112 -0
- package/dist/shell/store.js +134 -0
- package/dist/steps/index.d.ts +2 -0
- package/dist/steps/index.js +2 -0
- package/dist/steps/index.parts.d.ts +1 -0
- package/dist/steps/index.parts.js +5 -0
- package/dist/steps/steps.d.ts +90 -0
- package/dist/steps/steps.js +116 -0
- package/dist/tabs/anchored.d.ts +59 -0
- package/dist/tabs/anchored.js +109 -0
- package/dist/tabs/hover.d.ts +33 -0
- package/dist/tabs/hover.js +169 -0
- package/dist/tabs/index.d.ts +5 -0
- package/dist/tabs/index.js +4 -0
- package/dist/tabs/index.parts.d.ts +4 -0
- package/dist/tabs/index.parts.js +8 -0
- package/dist/tabs/store.d.ts +131 -0
- package/dist/tabs/store.js +248 -0
- package/dist/tabs/tabs.d.ts +217 -0
- package/dist/tabs/tabs.js +458 -0
- package/dist/thread/geometry.d.ts +23 -0
- package/dist/thread/geometry.js +48 -0
- package/dist/thread/index.d.ts +4 -0
- package/dist/thread/index.js +3 -0
- package/dist/thread/index.parts.d.ts +1 -0
- package/dist/thread/index.parts.js +5 -0
- package/dist/thread/stores.d.ts +21 -0
- package/dist/thread/stores.js +63 -0
- package/dist/thread/thread.d.ts +57 -0
- package/dist/thread/thread.js +663 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.js +17 -0
- package/package.json +120 -4
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List maths for an ordered, mutable collection.
|
|
3
|
+
*
|
|
4
|
+
* Base UI derives collection order from the DOM, walking
|
|
5
|
+
* `compareDocumentPosition`, because its collections are declarative children.
|
|
6
|
+
* Ours are not: the order is an array of ids on the store, so order is *data*
|
|
7
|
+
* and none of that machinery is needed. What is left is arithmetic, which is
|
|
8
|
+
* pure and therefore easy to be sure about.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Which item to land on when `removed` leaves the collection.
|
|
12
|
+
*
|
|
13
|
+
* The item that slides into the vacated slot, or the last one if the tail was
|
|
14
|
+
* removed — the same thing an editor does when you close a tab, and the
|
|
15
|
+
* closest thing to "stay where you were".
|
|
16
|
+
*/
|
|
17
|
+
export const adjacentTo = (items, removed,
|
|
18
|
+
/** Skips anything it rejects, searching outwards from the vacated slot. */
|
|
19
|
+
isEligible = () => true) => {
|
|
20
|
+
const index = items.indexOf(removed);
|
|
21
|
+
if (index === -1)
|
|
22
|
+
return null;
|
|
23
|
+
const remaining = items.filter((item) => item !== removed && isEligible(item));
|
|
24
|
+
if (remaining.length === 0)
|
|
25
|
+
return null;
|
|
26
|
+
// Everything that was after it, then everything before it, nearest first.
|
|
27
|
+
const after = items.slice(index + 1).find((item) => remaining.includes(item));
|
|
28
|
+
if (after !== undefined)
|
|
29
|
+
return after;
|
|
30
|
+
const before = items
|
|
31
|
+
.slice(0, index)
|
|
32
|
+
.reverse()
|
|
33
|
+
.find((item) => remaining.includes(item));
|
|
34
|
+
return before ?? null;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Step one place through the collection.
|
|
38
|
+
*
|
|
39
|
+
* From nothing, arrive at whichever end you are heading away from. At an edge,
|
|
40
|
+
* either wrap or stay put.
|
|
41
|
+
*/
|
|
42
|
+
export const step = (items, from, direction, { loop = true } = {}) => {
|
|
43
|
+
const last = items.length - 1;
|
|
44
|
+
if (last < 0)
|
|
45
|
+
return null;
|
|
46
|
+
const index = from === null ? -1 : items.indexOf(from);
|
|
47
|
+
if (index === -1)
|
|
48
|
+
return (direction === 1 ? items[0] : items[last]) ?? null;
|
|
49
|
+
const next = index + direction;
|
|
50
|
+
if (next < 0)
|
|
51
|
+
return (loop ? items[last] : items[0]) ?? null;
|
|
52
|
+
if (next > last)
|
|
53
|
+
return (loop ? items[0] : items[last]) ?? null;
|
|
54
|
+
return items[next] ?? null;
|
|
55
|
+
};
|
|
56
|
+
/** Move an item to a new position, clamping the target into range. */
|
|
57
|
+
export const moveTo = (items, id, toIndex) => {
|
|
58
|
+
const from = items.indexOf(id);
|
|
59
|
+
if (from === -1)
|
|
60
|
+
return items;
|
|
61
|
+
const without = items.filter((item) => item !== id);
|
|
62
|
+
const target = Math.min(Math.max(toIndex, 0), without.length);
|
|
63
|
+
return [...without.slice(0, target), id, ...without.slice(target)];
|
|
64
|
+
};
|
|
65
|
+
/** Insert an item, or move it if it is already present. Defaults to the end. */
|
|
66
|
+
export const insertAt = (items, id, index) => {
|
|
67
|
+
const without = items.filter((item) => item !== id);
|
|
68
|
+
if (index === undefined)
|
|
69
|
+
return [...without, id];
|
|
70
|
+
const target = Math.min(Math.max(index, 0), without.length);
|
|
71
|
+
return [...without.slice(0, target), id, ...without.slice(target)];
|
|
72
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect, useLayoutEffect } from "react";
|
|
3
|
+
// SSR-safe layout effect. There is no layout to read on the server, so it
|
|
4
|
+
// degrades to useEffect there; on the client it still runs before paint, which
|
|
5
|
+
// is the whole point for anything that measures or corrects the DOM.
|
|
6
|
+
export const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
// The one way the package portals. A portal can't be server-rendered — there is
|
|
5
|
+
// no document to portal into — so the first client render must stay empty too,
|
|
6
|
+
// or hydration won't match. useSyncExternalStore renders the server snapshot
|
|
7
|
+
// (false) while hydrating and re-renders with the client one right after; a
|
|
8
|
+
// client-only mount gets true straight away.
|
|
9
|
+
const getSnapshot = () => true;
|
|
10
|
+
const getServerSnapshot = () => false;
|
|
11
|
+
const subscribe = () => () => { };
|
|
12
|
+
const useHydrated = () => useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
13
|
+
export const Portal = ({ children, container }) => {
|
|
14
|
+
const hydrated = useHydrated();
|
|
15
|
+
if (!hydrated)
|
|
16
|
+
return null;
|
|
17
|
+
return createPortal(children, container ?? document.body);
|
|
18
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
import type { RenderComponentProps } from "./render/types.js";
|
|
3
|
+
export type EmptyState = Record<string, never>;
|
|
4
|
+
export type PrimitiveProps<ElementType extends React.ElementType, State = EmptyState> = RenderComponentProps<ElementType, State>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
export type HTMLProps<T = any> = React.HTMLAttributes<T> & {
|
|
3
|
+
ref?: React.Ref<T> | undefined;
|
|
4
|
+
};
|
|
5
|
+
export type WithDataAttributes<Props> = Props | (Props & {
|
|
6
|
+
[dataAttribute: `data-${string}`]: string | undefined;
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Shape of the render prop: a function that takes props to be spread on the element and component's state and returns a React element.
|
|
10
|
+
*
|
|
11
|
+
* @template Props Props to be spread on the rendered element.
|
|
12
|
+
* @template State Component's internal state.
|
|
13
|
+
*/
|
|
14
|
+
export type ComponentRenderFn<Props, State> = (props: Props, state: State) => React.ReactElement<unknown>;
|
|
15
|
+
export type PreventableEvent<E extends React.SyntheticEvent<Element, Event>> = E & {
|
|
16
|
+
preventPrimitiveHandler: () => void;
|
|
17
|
+
readonly primitiveHandlerPrevented?: boolean | undefined;
|
|
18
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Vendored from @base-ui/react v1.6.0 (MIT) — packages/react/src/types/index.ts
|
|
2
|
+
// https://github.com/mui/base-ui — subset: the upstream event-details re-export is
|
|
3
|
+
// dropped (unused by the render machinery) and names made neutral; otherwise an exact copy.
|
|
4
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Vendored from @base-ui/utils v1.6.0 (MIT) — packages/utils/src/getReactElementRef.ts
|
|
2
|
+
// https://github.com/mui/base-ui — exact copy.
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { isReactVersionAtLeast } from './reactVersion.js';
|
|
5
|
+
/**
|
|
6
|
+
* Extracts the `ref` from a React element, handling different React versions.
|
|
7
|
+
*/
|
|
8
|
+
export function getReactElementRef(element) {
|
|
9
|
+
if (!React.isValidElement(element)) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const reactElement = element;
|
|
13
|
+
const propsWithRef = reactElement.props;
|
|
14
|
+
return (isReactVersionAtLeast(19) ? propsWithRef?.ref : reactElement.ref) ?? null;
|
|
15
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type StateAttributesMapping<State> = {
|
|
2
|
+
[Property in keyof State]?: (state: State[Property]) => Record<string, string> | null;
|
|
3
|
+
};
|
|
4
|
+
export declare function getStateAttributesProps<State extends Record<string, any>>(state: State, customMapping?: StateAttributesMapping<State>): Record<string, string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Vendored from @base-ui/react v1.6.0 (MIT) — packages/react/src/internals/getStateAttributesProps.ts
|
|
2
|
+
// https://github.com/mui/base-ui — exact copy.
|
|
3
|
+
export function getStateAttributesProps(state, customMapping) {
|
|
4
|
+
const props = {};
|
|
5
|
+
/* eslint-disable-next-line guard-for-in */
|
|
6
|
+
for (const key in state) {
|
|
7
|
+
const value = state[key];
|
|
8
|
+
if (customMapping?.hasOwnProperty(key)) {
|
|
9
|
+
const customProps = customMapping[key](value);
|
|
10
|
+
if (customProps != null) {
|
|
11
|
+
Object.assign(props, customProps);
|
|
12
|
+
}
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (value === true) {
|
|
16
|
+
props[`data-${key.toLowerCase()}`] = '';
|
|
17
|
+
}
|
|
18
|
+
else if (value) {
|
|
19
|
+
props[`data-${key.toLowerCase()}`] = value.toString();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return props;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function mergeObjects<A extends object | undefined, B extends object | undefined>(a: A, b: B): NonNullable<A> | NonNullable<B> | (A & B) | undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Vendored from @base-ui/utils v1.6.0 (MIT) — packages/utils/src/mergeObjects.ts
|
|
2
|
+
// https://github.com/mui/base-ui — exact copy.
|
|
3
|
+
export function mergeObjects(a, b) {
|
|
4
|
+
if (a && !b) {
|
|
5
|
+
return a;
|
|
6
|
+
}
|
|
7
|
+
if (!a && b) {
|
|
8
|
+
return b;
|
|
9
|
+
}
|
|
10
|
+
if (a || b) {
|
|
11
|
+
return { ...a, ...b };
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PreventableEvent, WithPreventableEvents } from './types.js';
|
|
3
|
+
type ElementType = React.ElementType;
|
|
4
|
+
type PropsOf<T extends React.ElementType> = WithPreventableEvents<React.ComponentPropsWithRef<T>>;
|
|
5
|
+
type InputProps<T extends React.ElementType> = PropsOf<T> | ((otherProps: PropsOf<T>) => PropsOf<T>) | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Merges multiple sets of React props. It follows the Object.assign pattern where the rightmost object's fields overwrite
|
|
8
|
+
* the conflicting ones from others. This doesn't apply to event handlers, `className` and `style` props.
|
|
9
|
+
*
|
|
10
|
+
* Event handlers are merged and called in right-to-left order (rightmost handler executes first, leftmost last).
|
|
11
|
+
* For React synthetic events, the rightmost handler can prevent prior (left-positioned) handlers from executing
|
|
12
|
+
* by calling `event.preventPrimitiveHandler()`. For non-synthetic events (custom events with primitive/object values),
|
|
13
|
+
* all handlers always execute without prevention capability.
|
|
14
|
+
*
|
|
15
|
+
* The `className` prop is merged by concatenating classes in right-to-left order (rightmost class appears first in the string).
|
|
16
|
+
* The `style` prop is merged with rightmost styles overwriting the prior ones.
|
|
17
|
+
*
|
|
18
|
+
* Props can either be provided as objects or as functions that take the previous props as an argument.
|
|
19
|
+
* The function will receive the merged props up to that point (going from left to right):
|
|
20
|
+
* so in the case of `(obj1, obj2, fn, obj3)`, `fn` will receive the merged props of `obj1` and `obj2`.
|
|
21
|
+
* The function is responsible for chaining event handlers if needed (that is, we don't run the merge logic).
|
|
22
|
+
*
|
|
23
|
+
* Event handlers returned by the functions are not automatically prevented when `preventPrimitiveHandler` is called.
|
|
24
|
+
* They must check `event.primitiveHandlerPrevented` themselves and bail out if it's true.
|
|
25
|
+
*
|
|
26
|
+
* @important **`ref` is not merged.**
|
|
27
|
+
* @param a Props object to merge.
|
|
28
|
+
* @param b Props object to merge. The function will overwrite conflicting props from `a`.
|
|
29
|
+
* @param c Props object to merge. The function will overwrite conflicting props from previous parameters.
|
|
30
|
+
* @param d Props object to merge. The function will overwrite conflicting props from previous parameters.
|
|
31
|
+
* @param e Props object to merge. The function will overwrite conflicting props from previous parameters.
|
|
32
|
+
* @returns The merged props.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export declare function mergeProps<T extends ElementType>(a: InputProps<T>, b: InputProps<T>, c: InputProps<T>, d: InputProps<T>, e: InputProps<T>): PropsOf<T>;
|
|
36
|
+
export declare function mergeProps<T extends ElementType>(a: InputProps<T>, b: InputProps<T>, c: InputProps<T>, d: InputProps<T>): PropsOf<T>;
|
|
37
|
+
export declare function mergeProps<T extends ElementType>(a: InputProps<T>, b: InputProps<T>, c: InputProps<T>): PropsOf<T>;
|
|
38
|
+
export declare function mergeProps<T extends ElementType>(a: InputProps<T>, b: InputProps<T>): PropsOf<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Merges an arbitrary number of React props using the same logic as {@link mergeProps}.
|
|
41
|
+
* This function accepts an array of props instead of individual arguments.
|
|
42
|
+
*
|
|
43
|
+
* This has slightly lower performance than {@link mergeProps} due to accepting an array
|
|
44
|
+
* instead of a fixed number of arguments. Prefer {@link mergeProps} when merging 5 or
|
|
45
|
+
* fewer prop sets for better performance.
|
|
46
|
+
*
|
|
47
|
+
* @param props Array of props to merge.
|
|
48
|
+
* @returns The merged props.
|
|
49
|
+
* @see mergeProps
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
export declare function mergePropsN<T extends ElementType>(props: InputProps<T>[]): PropsOf<T>;
|
|
53
|
+
export declare function makeEventPreventable<T extends React.SyntheticEvent>(event: PreventableEvent<T>): PreventableEvent<T>;
|
|
54
|
+
export declare function mergeClassNames(ourClassName: string | undefined, theirClassName: string | undefined): string | undefined;
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// Vendored from @base-ui/react v1.6.0 (MIT) — packages/react/src/merge-props/mergeProps.ts
|
|
2
|
+
// https://github.com/mui/base-ui — import specifiers rewired and names made neutral; otherwise an exact copy.
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { mergeObjects } from './mergeObjects.js';
|
|
5
|
+
const EMPTY_PROPS = {};
|
|
6
|
+
export function mergeProps(a, b, c, d, e) {
|
|
7
|
+
if (!c && !d && !e && !a) {
|
|
8
|
+
return createInitialMergedProps(b);
|
|
9
|
+
}
|
|
10
|
+
// We need to mutably own `merged`.
|
|
11
|
+
let merged = createInitialMergedProps(a);
|
|
12
|
+
if (b) {
|
|
13
|
+
merged = mergeInto(merged, b);
|
|
14
|
+
}
|
|
15
|
+
if (c) {
|
|
16
|
+
merged = mergeInto(merged, c);
|
|
17
|
+
}
|
|
18
|
+
if (d) {
|
|
19
|
+
merged = mergeInto(merged, d);
|
|
20
|
+
}
|
|
21
|
+
if (e) {
|
|
22
|
+
merged = mergeInto(merged, e);
|
|
23
|
+
}
|
|
24
|
+
return merged;
|
|
25
|
+
}
|
|
26
|
+
/* eslint-enable id-denylist */
|
|
27
|
+
/**
|
|
28
|
+
* Merges an arbitrary number of React props using the same logic as {@link mergeProps}.
|
|
29
|
+
* This function accepts an array of props instead of individual arguments.
|
|
30
|
+
*
|
|
31
|
+
* This has slightly lower performance than {@link mergeProps} due to accepting an array
|
|
32
|
+
* instead of a fixed number of arguments. Prefer {@link mergeProps} when merging 5 or
|
|
33
|
+
* fewer prop sets for better performance.
|
|
34
|
+
*
|
|
35
|
+
* @param props Array of props to merge.
|
|
36
|
+
* @returns The merged props.
|
|
37
|
+
* @see mergeProps
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export function mergePropsN(props) {
|
|
41
|
+
if (props.length === 0) {
|
|
42
|
+
return EMPTY_PROPS;
|
|
43
|
+
}
|
|
44
|
+
if (props.length === 1) {
|
|
45
|
+
return createInitialMergedProps(props[0]);
|
|
46
|
+
}
|
|
47
|
+
// We need to mutably own `merged`.
|
|
48
|
+
let merged = createInitialMergedProps(props[0]);
|
|
49
|
+
for (let i = 1; i < props.length; i += 1) {
|
|
50
|
+
merged = mergeInto(merged, props[i]);
|
|
51
|
+
}
|
|
52
|
+
return merged;
|
|
53
|
+
}
|
|
54
|
+
function createInitialMergedProps(inputProps) {
|
|
55
|
+
if (isPropsGetter(inputProps)) {
|
|
56
|
+
// Getter-returned handlers intentionally keep their existing semantics.
|
|
57
|
+
return { ...resolvePropsGetter(inputProps, EMPTY_PROPS) };
|
|
58
|
+
}
|
|
59
|
+
return copyInitialProps(inputProps);
|
|
60
|
+
}
|
|
61
|
+
function mergeInto(merged, inputProps) {
|
|
62
|
+
if (isPropsGetter(inputProps)) {
|
|
63
|
+
return resolvePropsGetter(inputProps, merged);
|
|
64
|
+
}
|
|
65
|
+
return mutablyMergeInto(merged, inputProps);
|
|
66
|
+
}
|
|
67
|
+
function copyInitialProps(inputProps) {
|
|
68
|
+
const copiedProps = { ...inputProps };
|
|
69
|
+
// `copiedProps` is our fresh own-object copy, so iterating with `for...in` is safe here.
|
|
70
|
+
// eslint-disable-next-line guard-for-in
|
|
71
|
+
for (const propName in copiedProps) {
|
|
72
|
+
const propValue = copiedProps[propName];
|
|
73
|
+
if (isEventHandler(propName, propValue)) {
|
|
74
|
+
copiedProps[propName] = wrapEventHandler(propValue);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return copiedProps;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Merges two sets of props. In case of conflicts, the external props take precedence.
|
|
81
|
+
*/
|
|
82
|
+
function mutablyMergeInto(mergedProps, externalProps) {
|
|
83
|
+
if (!externalProps) {
|
|
84
|
+
return mergedProps;
|
|
85
|
+
}
|
|
86
|
+
// eslint-disable-next-line guard-for-in
|
|
87
|
+
for (const propName in externalProps) {
|
|
88
|
+
const externalPropValue = externalProps[propName];
|
|
89
|
+
switch (propName) {
|
|
90
|
+
case 'style': {
|
|
91
|
+
mergedProps[propName] = mergeObjects(mergedProps.style, externalPropValue);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case 'className': {
|
|
95
|
+
mergedProps[propName] = mergeClassNames(mergedProps.className, externalPropValue);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
default: {
|
|
99
|
+
if (isEventHandler(propName, externalPropValue)) {
|
|
100
|
+
mergedProps[propName] = mergeEventHandlers(mergedProps[propName], externalPropValue);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
mergedProps[propName] = externalPropValue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return mergedProps;
|
|
109
|
+
}
|
|
110
|
+
function isEventHandler(key, value) {
|
|
111
|
+
// This approach is more efficient than using a regex.
|
|
112
|
+
const code0 = key.charCodeAt(0);
|
|
113
|
+
const code1 = key.charCodeAt(1);
|
|
114
|
+
const code2 = key.charCodeAt(2);
|
|
115
|
+
return (code0 === 111 /* o */ &&
|
|
116
|
+
code1 === 110 /* n */ &&
|
|
117
|
+
code2 >= 65 /* A */ &&
|
|
118
|
+
code2 <= 90 /* Z */ &&
|
|
119
|
+
(typeof value === 'function' || typeof value === 'undefined'));
|
|
120
|
+
}
|
|
121
|
+
function isPropsGetter(inputProps) {
|
|
122
|
+
return typeof inputProps === 'function';
|
|
123
|
+
}
|
|
124
|
+
function resolvePropsGetter(inputProps, previousProps) {
|
|
125
|
+
if (isPropsGetter(inputProps)) {
|
|
126
|
+
return inputProps(previousProps);
|
|
127
|
+
}
|
|
128
|
+
return inputProps ?? EMPTY_PROPS;
|
|
129
|
+
}
|
|
130
|
+
function mergeEventHandlers(ourHandler, theirHandler) {
|
|
131
|
+
if (!theirHandler) {
|
|
132
|
+
return ourHandler;
|
|
133
|
+
}
|
|
134
|
+
if (!ourHandler) {
|
|
135
|
+
return wrapEventHandler(theirHandler);
|
|
136
|
+
}
|
|
137
|
+
return (...args) => {
|
|
138
|
+
const event = args[0];
|
|
139
|
+
if (isSyntheticEvent(event)) {
|
|
140
|
+
const preventableEvent = event;
|
|
141
|
+
makeEventPreventable(preventableEvent);
|
|
142
|
+
const result = theirHandler(...args);
|
|
143
|
+
if (!preventableEvent.primitiveHandlerPrevented) {
|
|
144
|
+
ourHandler?.(...args);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
const result = theirHandler(...args);
|
|
149
|
+
ourHandler?.(...args);
|
|
150
|
+
return result;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function wrapEventHandler(handler) {
|
|
154
|
+
if (!handler) {
|
|
155
|
+
return handler;
|
|
156
|
+
}
|
|
157
|
+
return (...args) => {
|
|
158
|
+
const event = args[0];
|
|
159
|
+
if (isSyntheticEvent(event)) {
|
|
160
|
+
makeEventPreventable(event);
|
|
161
|
+
}
|
|
162
|
+
return handler(...args);
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export function makeEventPreventable(event) {
|
|
166
|
+
event.preventPrimitiveHandler = () => {
|
|
167
|
+
event.primitiveHandlerPrevented = true;
|
|
168
|
+
};
|
|
169
|
+
return event;
|
|
170
|
+
}
|
|
171
|
+
export function mergeClassNames(ourClassName, theirClassName) {
|
|
172
|
+
if (theirClassName) {
|
|
173
|
+
if (ourClassName) {
|
|
174
|
+
// eslint-disable-next-line prefer-template
|
|
175
|
+
return theirClassName + ' ' + ourClassName;
|
|
176
|
+
}
|
|
177
|
+
return theirClassName;
|
|
178
|
+
}
|
|
179
|
+
return ourClassName;
|
|
180
|
+
}
|
|
181
|
+
function isSyntheticEvent(event) {
|
|
182
|
+
return event != null && typeof event === 'object' && 'nativeEvent' in event;
|
|
183
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
export type AnchorSide = "top" | "bottom" | "left" | "right";
|
|
3
|
+
export type AnchorAlign = "start" | "center" | "end";
|
|
4
|
+
export type UseAnchorPositioningOptions = {
|
|
5
|
+
/** Position only while true (e.g. while the surface is mounted/open). */
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
/** Preferred side; flips to the opposite when there's no room. Default "top". */
|
|
8
|
+
side?: AnchorSide;
|
|
9
|
+
/** Alignment along the side. Default "center". */
|
|
10
|
+
align?: AnchorAlign;
|
|
11
|
+
/** Gap between anchor and floating element. Default 0. */
|
|
12
|
+
sideOffset?: number;
|
|
13
|
+
/** Keep this many px from the collision boundary. Default 8. */
|
|
14
|
+
collisionPadding?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Pin to `side`/`align` without collision repositioning — drops flip + shift, so the surface
|
|
17
|
+
* stays put and may run off-screen when there's no room. `size` still publishes its vars.
|
|
18
|
+
* Default false.
|
|
19
|
+
*/
|
|
20
|
+
pin?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Called with the resolved placement every time one lands — which is what flip and shift may
|
|
23
|
+
* have changed it to, not necessarily what was asked for. Fires on every reposition, so a
|
|
24
|
+
* caller holding it in state must compare before setting. Until the first call the surface has
|
|
25
|
+
* no left/top, so a consumer that transitions those should withhold paint rather than animate
|
|
26
|
+
* in from 0,0.
|
|
27
|
+
*/
|
|
28
|
+
onPositioned?: (placement: {
|
|
29
|
+
side: AnchorSide;
|
|
30
|
+
align: AnchorAlign;
|
|
31
|
+
}) => void;
|
|
32
|
+
};
|
|
33
|
+
export declare const useAnchorPositioning: (getAnchor: () => Element | null, floatingRef: RefObject<HTMLElement | null>, { enabled, side, align, sideOffset, collisionPadding, pin, onPositioned, }?: UseAnchorPositioningOptions) => void;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// Collision-aware anchor positioning via @floating-ui/dom, shared by Composer.Popover
|
|
3
|
+
// (anchored to the active command badge) and a positioned Composer.Panel (anchored to the
|
|
4
|
+
// composer container). Positions the floating element with flip/shift/size and keeps it there
|
|
5
|
+
// across scroll/resize/anchor movement (autoUpdate); `pin` opts out of flip/shift.
|
|
6
|
+
//
|
|
7
|
+
// Everything is written imperatively — no per-render React state — so a flip or a scroll never
|
|
8
|
+
// re-renders the tree: `position: absolute` + left/top (page coordinates, so the surface scrolls
|
|
9
|
+
// natively with the page instead of chasing the anchor a frame behind it); `--anchor-width` /
|
|
10
|
+
// `--anchor-height` (the anchor's own size, e.g. so a panel can be `width: var(--anchor-width)`)
|
|
11
|
+
// and `--anchor-available-height` / `--anchor-available-width` (free space in the placement
|
|
12
|
+
// direction — cap max-height + scroll instead of overflow) from the size middleware; and
|
|
13
|
+
// `data-side`/`data-align` for the transition origin. Base UI-style: the styling layer opts into
|
|
14
|
+
// the vars, the primitive imposes nothing.
|
|
15
|
+
import { autoUpdate, computePosition, flip, offset, shift, size, } from "@floating-ui/dom";
|
|
16
|
+
import { useEffect } from "react";
|
|
17
|
+
const EMPTY_RECT = {
|
|
18
|
+
x: 0,
|
|
19
|
+
y: 0,
|
|
20
|
+
width: 0,
|
|
21
|
+
height: 0,
|
|
22
|
+
top: 0,
|
|
23
|
+
right: 0,
|
|
24
|
+
bottom: 0,
|
|
25
|
+
left: 0,
|
|
26
|
+
toJSON: () => "",
|
|
27
|
+
};
|
|
28
|
+
export const useAnchorPositioning = (getAnchor, floatingRef, { enabled = true, side = "top", align = "center", sideOffset = 0, collisionPadding = 8, pin = false, onPositioned, } = {}) => {
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const floating = floatingRef.current;
|
|
31
|
+
if (!enabled || !floating)
|
|
32
|
+
return;
|
|
33
|
+
const placement = (align === "center" ? side : `${side}-${align}`);
|
|
34
|
+
// Out of flow *before* anything is measured. A static element portaled into a flex or
|
|
35
|
+
// grid container is a layout participant, and a 500px participant shoves its siblings —
|
|
36
|
+
// including the anchor — somewhere else for exactly the measurement that matters.
|
|
37
|
+
floating.style.position = "absolute";
|
|
38
|
+
// Withhold paint until the first placement lands, since until then the surface has no
|
|
39
|
+
// left/top and would otherwise show at 0,0 for a frame — and a consumer transitioning
|
|
40
|
+
// left/top would animate it in from the corner (`auto` → a length is not interpolable).
|
|
41
|
+
// `data-side` is written below and by nothing else, so its absence means "never placed".
|
|
42
|
+
if (!floating.hasAttribute("data-side")) {
|
|
43
|
+
floating.style.visibility = "hidden";
|
|
44
|
+
}
|
|
45
|
+
// Virtual reference: re-reads the anchor rect each run, so a re-created anchor (e.g. the
|
|
46
|
+
// command badge decoration re-rendering as you type) is tracked without re-subscribing.
|
|
47
|
+
const reference = {
|
|
48
|
+
getBoundingClientRect: () => getAnchor()?.getBoundingClientRect() ?? EMPTY_RECT,
|
|
49
|
+
get contextElement() {
|
|
50
|
+
return getAnchor() ?? undefined;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const update = () => {
|
|
54
|
+
// The first placement must land, not animate: a consumer transitioning
|
|
55
|
+
// left/top would otherwise slide the surface in from wherever the browser
|
|
56
|
+
// had it before there were coordinates at all.
|
|
57
|
+
const firstPlacement = !floating.hasAttribute("data-side");
|
|
58
|
+
computePosition(reference, floating, {
|
|
59
|
+
// Absolute (page-coordinate), not fixed: portaled to the body, the surface then
|
|
60
|
+
// scrolls *with* the page natively — so following the anchor on scroll needs no
|
|
61
|
+
// per-frame JS write and can't lag a frame behind it (the "wobble"). autoUpdate
|
|
62
|
+
// still re-runs for real layout changes (flip/shift/resize/anchor movement).
|
|
63
|
+
strategy: "absolute",
|
|
64
|
+
placement,
|
|
65
|
+
middleware: [
|
|
66
|
+
offset(sideOffset),
|
|
67
|
+
// Collision repositioning — skipped when pinned, so the surface holds `side`/`align`.
|
|
68
|
+
...(pin
|
|
69
|
+
? []
|
|
70
|
+
: [flip({ padding: collisionPadding }), shift({ padding: collisionPadding })]),
|
|
71
|
+
size({
|
|
72
|
+
padding: collisionPadding,
|
|
73
|
+
apply({ availableWidth, availableHeight, rects }) {
|
|
74
|
+
// Anchor's own size + the free space toward the placement side, published as
|
|
75
|
+
// vars for the styling layer to consume (e.g. `width: var(--anchor-width)`,
|
|
76
|
+
// `max-height: var(--anchor-available-height)`). Never sets width/height itself.
|
|
77
|
+
floating.style.setProperty("--anchor-width", `${Math.round(rects.reference.width)}px`);
|
|
78
|
+
floating.style.setProperty("--anchor-height", `${Math.round(rects.reference.height)}px`);
|
|
79
|
+
floating.style.setProperty("--anchor-available-height", `${Math.max(0, Math.round(availableHeight))}px`);
|
|
80
|
+
floating.style.setProperty("--anchor-available-width", `${Math.max(0, Math.round(availableWidth))}px`);
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
}).then(({ x, y, placement: resolved }) => {
|
|
85
|
+
if (firstPlacement)
|
|
86
|
+
floating.style.transition = "none";
|
|
87
|
+
floating.style.position = "absolute";
|
|
88
|
+
floating.style.left = `${Math.round(x)}px`;
|
|
89
|
+
floating.style.top = `${Math.round(y)}px`;
|
|
90
|
+
// Placed, so it may paint. Cleared rather than set to "visible", which would override
|
|
91
|
+
// a consumer hiding it for its own reasons.
|
|
92
|
+
floating.style.visibility = "";
|
|
93
|
+
const [resolvedSide = side, resolvedAlign = "center"] = resolved.split("-");
|
|
94
|
+
floating.setAttribute("data-side", resolvedSide);
|
|
95
|
+
floating.setAttribute("data-align", resolvedAlign);
|
|
96
|
+
onPositioned?.({
|
|
97
|
+
side: resolvedSide,
|
|
98
|
+
align: resolvedAlign,
|
|
99
|
+
});
|
|
100
|
+
// Flush the first coordinates into computed style while transitions are off, then
|
|
101
|
+
// hand the property back. A deferred restore (rAF) is not enough: rAF callbacks run
|
|
102
|
+
// *before* the frame's style recalc, so the recalc would still see `auto → x` with
|
|
103
|
+
// the consumer's transition live and animate it in from the static position.
|
|
104
|
+
if (firstPlacement) {
|
|
105
|
+
void floating.offsetHeight;
|
|
106
|
+
floating.style.transition = "";
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
return autoUpdate(reference, floating, update);
|
|
111
|
+
}, [enabled, getAnchor, floatingRef, side, align, sideOffset, collisionPadding, pin, onPositioned]);
|
|
112
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Vendored from @base-ui/utils v1.6.0 (MIT) — packages/utils/src/reactVersion.ts
|
|
2
|
+
// https://github.com/mui/base-ui — exact copy.
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
const majorVersion = parseInt(React.version, 10);
|
|
5
|
+
export function isReactVersionAtLeast(reactVersionToCheck) {
|
|
6
|
+
return majorVersion >= reactVersionToCheck;
|
|
7
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* If the provided className is a string, it will be returned as is.
|
|
3
|
+
* Otherwise, the function will call the className function with the state as the first argument.
|
|
4
|
+
*
|
|
5
|
+
* @param className
|
|
6
|
+
* @param state
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveClassName<State>(className: string | ((state: State) => string | undefined) | undefined, state: State): string | undefined;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Vendored from @base-ui/react v1.6.0 (MIT) — packages/react/src/utils/resolveClassName.ts
|
|
2
|
+
// https://github.com/mui/base-ui — exact copy.
|
|
3
|
+
/**
|
|
4
|
+
* If the provided className is a string, it will be returned as is.
|
|
5
|
+
* Otherwise, the function will call the className function with the state as the first argument.
|
|
6
|
+
*
|
|
7
|
+
* @param className
|
|
8
|
+
* @param state
|
|
9
|
+
*/
|
|
10
|
+
export function resolveClassName(className, state) {
|
|
11
|
+
return typeof className === 'function' ? className(state) : className;
|
|
12
|
+
}
|