@intentface/chat 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # @intentface/chat
2
2
 
3
3
  Headless chat UI primitives for React — the behavior, state, and wire formats
4
- for building AI chat interfaces, with no styling of their own. Pair them with
5
- the shadcn-style styled layer from the [docs](https://intentface.dev/docs), or
6
- bring your own.
4
+ for building AI chat interfaces, with no styling of their own.
7
5
 
8
- This is the Base UI model applied to chat: **install the logic from npm, copy
9
- the look from the docs.**
6
+ This is the Base UI model applied to chat: **the package owns behavior, you own
7
+ every class.** There is no pre-styled `@intentface/chat` package. The demos on
8
+ each [docs](https://intentface.dev/docs) page show how the parts fit together
9
+ and are meant to be copied and restyled.
10
10
 
11
11
  ## Status
12
12
 
@@ -100,7 +100,7 @@ directive and import fine anywhere.
100
100
 
101
101
  ## Docs
102
102
 
103
- Full guides, live previews, and copy-paste styled source at
103
+ Full guides, live demos, and the API reference at
104
104
  [intentface.dev/docs](https://intentface.dev/docs).
105
105
 
106
106
  ## License
@@ -3,7 +3,9 @@
3
3
  // token, so a rendered message reconstructs the chip from its own text
4
4
  // alone — no sidecar metadata array. Presentation that's derivable at render
5
5
  // time (e.g. a per-prefix variant) is the renderer's job, not wire data.
6
- export const CHIP_REF_PATTERN = /\[([^\]]+)\]\(chip:([^:)]+):([^)?]+)(?:\?([^)]*))?\)/g;
6
+ // Every class excludes "[" so no group can consume past the next one — without
7
+ // that this backtracks quadratically, and message text is untrusted.
8
+ export const CHIP_REF_PATTERN = /\[([^[\]]+)\]\(chip:([^[:)]+):([^[)?]+)(?:\?([^[)]*))?\)/g;
7
9
  export const escapeMarkdownLink = (input) => input.replace(/[[\]()\\]/g, (match) => `\\${match}`);
8
10
  // Tolerate legacy/un-encoded values — a stray "%" would otherwise throw and
9
11
  // take the whole message render down with it.
@@ -2,6 +2,11 @@
2
2
  // active-token state shape and the pure scan that derives it from the text
3
3
  // around the caret. Sticky range tracking and dismissal memory live one layer
4
4
  // up, in trigger-tracker.ts.
5
+ // ---------------------------------------------------------------------------
6
+ // Types & constants
7
+ // ---------------------------------------------------------------------------
8
+ // Non-global: `.test` on a global regex advances lastIndex between calls.
9
+ const WHITESPACE = /\s/;
5
10
  export const CLOSED_COMMAND_STATE = {
6
11
  isOpen: false,
7
12
  trigger: null,
@@ -34,16 +39,20 @@ export const detectActivePrefix = (args) => {
34
39
  // taken from both sides of the caret so it stays whole as the caret moves
35
40
  // within it. Text chars map 1:1 to positions and an atomic chip can never
36
41
  // sit inside a run, so the run length is the position delta on each side.
37
- const leftRun = textBeforeCursor.match(/\S*$/)?.[0] ?? "";
42
+ // Scanned backwards, not /\S*$/ that backtracks quadratically when the
43
+ // text ends in whitespace, on a path that runs per keystroke.
44
+ let runStart = textBeforeCursor.length;
45
+ while (runStart > 0 && !WHITESPACE.test(textBeforeCursor[runStart - 1]))
46
+ runStart--;
47
+ const leftRun = textBeforeCursor.slice(runStart);
48
+ // Start-anchored, so this one cannot backtrack.
38
49
  const rightRun = textAfterCursor.match(/^\S*/)?.[0] ?? "";
39
50
  const runText = leftRun + rightRun;
40
51
  if (!runText.startsWith(entry.prefix))
41
52
  continue;
42
53
  // The prefix must sit at a word boundary: line start or after whitespace.
43
- const charBeforeRun = textBeforeCursor
44
- .slice(0, textBeforeCursor.length - leftRun.length)
45
- .at(-1);
46
- if (charBeforeRun !== undefined && !/\s/.test(charBeforeRun))
54
+ const charBeforeRun = runStart > 0 ? textBeforeCursor[runStart - 1] : undefined;
55
+ if (charBeforeRun !== undefined && !WHITESPACE.test(charBeforeRun))
47
56
  continue;
48
57
  return {
49
58
  isOpen: true,
@@ -1,7 +1,7 @@
1
1
  // Vendored from @base-ui/utils v1.6.0 (MIT) — packages/utils/src/getReactElementRef.ts
2
2
  // https://github.com/mui/base-ui — exact copy.
3
3
  import * as React from 'react';
4
- import { isReactVersionAtLeast } from './reactVersion';
4
+ import { isReactVersionAtLeast } from './reactVersion.js';
5
5
  /**
6
6
  * Extracts the `ref` from a React element, handling different React versions.
7
7
  */
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type { BaseUIEvent, WithBaseUIEvent } from './types';
2
+ import type { BaseUIEvent, WithBaseUIEvent } from './types.js';
3
3
  type ElementType = React.ElementType;
4
4
  type PropsOf<T extends React.ElementType> = WithBaseUIEvent<React.ComponentPropsWithRef<T>>;
5
5
  type InputProps<T extends React.ElementType> = PropsOf<T> | ((otherProps: PropsOf<T>) => PropsOf<T>) | undefined;
@@ -1,7 +1,7 @@
1
1
  // Vendored from @base-ui/react v1.6.0 (MIT) — packages/react/src/merge-props/mergeProps.ts
2
2
  // https://github.com/mui/base-ui — exact copy; only import specifiers rewired.
3
3
  import * as React from 'react';
4
- import { mergeObjects } from './mergeObjects';
4
+ import { mergeObjects } from './mergeObjects.js';
5
5
  const EMPTY_PROPS = {};
6
6
  export function mergeProps(a, b, c, d, e) {
7
7
  if (!c && !d && !e && !a) {
@@ -1,5 +1,5 @@
1
1
  import type * as React from 'react';
2
- import type { BaseUIEvent, ComponentRenderFn, HTMLProps } from './baseTypes';
2
+ import type { BaseUIEvent, ComponentRenderFn, HTMLProps } from './baseTypes.js';
3
3
  export type { HTMLProps, BaseUIEvent, ComponentRenderFn };
4
4
  export type MaybeBaseUIEvent<E extends React.SyntheticEvent<Element, Event>> = E & Partial<Pick<BaseUIEvent<E>, 'preventBaseUIHandler' | 'baseUIHandlerPrevented'>>;
5
5
  export interface FloatingUIOpenChangeDetails {
@@ -1,7 +1,7 @@
1
1
  // Vendored from @base-ui/utils v1.6.0 (MIT) — packages/utils/src/useMergedRefs.ts
2
2
  // https://github.com/mui/base-ui — exact copy.
3
3
  import * as React from 'react';
4
- import { useRefWithInit } from './useRefWithInit';
4
+ import { useRefWithInit } from './useRefWithInit.js';
5
5
  export function useMergedRefs(a, b, c, d) {
6
6
  const forkRef = useRefWithInit((createForkRef)).current;
7
7
  if (didChange(forkRef, a, b, c, d)) {
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
- import type { ComponentRenderFn } from './types';
3
- import type { HTMLProps } from './types';
4
- import type { StateAttributesMapping } from './getStateAttributesProps';
2
+ import type { ComponentRenderFn } from './types.js';
3
+ import type { HTMLProps } from './types.js';
4
+ import type { StateAttributesMapping } from './getStateAttributesProps.js';
5
5
  /**
6
6
  * Renders a Base UI element.
7
7
  *
@@ -1,7 +1,7 @@
1
1
  // Vendored from @base-ui/react v1.6.0 (MIT) — packages/react/src/use-render/useRender.ts
2
2
  // https://github.com/mui/base-ui — exact copy; only import specifiers rewired.
3
3
  import * as React from 'react';
4
- import { useRenderElement } from './useRenderElement';
4
+ import { useRenderElement } from './useRenderElement.js';
5
5
  /**
6
6
  * Renders a Base UI element.
7
7
  *
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
- import type { ComponentRenderFn, HTMLProps } from './types';
3
- import type { WithDataAttributes } from './baseTypes';
4
- import { type StateAttributesMapping } from './getStateAttributesProps';
2
+ import type { ComponentRenderFn, HTMLProps } from './types.js';
3
+ import type { WithDataAttributes } from './baseTypes.js';
4
+ import { type StateAttributesMapping } from './getStateAttributesProps.js';
5
5
  type IntrinsicTagName = keyof React.JSX.IntrinsicElements;
6
6
  /**
7
7
  * Renders a Base UI element.
@@ -3,15 +3,15 @@ import { createElement as _createElement } from "react";
3
3
  // https://github.com/mui/base-ui — import specifiers rewired; one local departure:
4
4
  // the `props` config accepts bespoke data-* part attributes (WithDataAttributes).
5
5
  import * as React from 'react';
6
- import { useMergedRefs, useMergedRefsN } from './useMergedRefs';
7
- import { getReactElementRef } from './getReactElementRef';
8
- import { mergeObjects } from './mergeObjects';
9
- import { warn } from './warn';
10
- import { EMPTY_OBJECT } from './empty';
11
- import { getStateAttributesProps } from './getStateAttributesProps';
12
- import { resolveClassName } from './resolveClassName';
13
- import { resolveStyle } from './resolveStyle';
14
- import { mergeProps, mergePropsN, mergeClassNames } from './mergeProps';
6
+ import { useMergedRefs, useMergedRefsN } from './useMergedRefs.js';
7
+ import { getReactElementRef } from './getReactElementRef.js';
8
+ import { mergeObjects } from './mergeObjects.js';
9
+ import { warn } from './warn.js';
10
+ import { EMPTY_OBJECT } from './empty.js';
11
+ import { getStateAttributesProps } from './getStateAttributesProps.js';
12
+ import { resolveClassName } from './resolveClassName.js';
13
+ import { resolveStyle } from './resolveStyle.js';
14
+ import { mergeProps, mergePropsN, mergeClassNames } from './mergeProps.js';
15
15
  /**
16
16
  * Renders a Base UI element.
17
17
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentface/chat",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Headless chat UI primitives — unstyled compound components, hooks, and wire formats for building AI chat interfaces.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -77,7 +77,7 @@
77
77
  }
78
78
  },
79
79
  "scripts": {
80
- "build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/add-dist-extensions.mjs",
80
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/add-dist-extensions.mjs && node scripts/smoke-dist.mjs",
81
81
  "test": "bun test",
82
82
  "typecheck": "tsc --noEmit",
83
83
  "prepack": "bun run build && node scripts/swap-exports.mjs pre",