diff --git a/src/uix/active-uix/id/create-id.ts b/src/uix/active-uix/id/create-id.ts new file mode 100644 index 000000000..b687e4d01 --- /dev/null +++ b/src/uix/active-uix/id/create-id.ts @@ -0,0 +1,20 @@ +/** + * Create an id from a Svelte `$props.id()` uid, with optional component context. + * + * ```ts + * createId(uid) // "soma-c12" + * createId(uid, 'dialog-trigger') // "soma-dialog-trigger-c12" + * ``` + * + * The `uid` comes from the consuming component's `$props.id()`, so the output + * is hydration-stable (deterministic per render tree) — use this for SSR / ARIA + * element ids. For a generic client-only counter, use `useId` (same module). + * + * Lives in active-uix (imported by subpath `$active-uix/id`) so every UIX layer + * — soma, eidos, demos, apps — shares one id authority without cross-layer + * coupling. The `soma-` prefix is the UIX id convention, kept for output + * stability across the migration. + */ +export function createId(uid: string, component?: string): string { + return component ? `soma-${component}-${uid}` : `soma-${uid}` +} diff --git a/src/uix/active-uix/id/index.ts b/src/uix/active-uix/id/index.ts index 4c8e40f3b..0f9e99318 100644 --- a/src/uix/active-uix/id/index.ts +++ b/src/uix/active-uix/id/index.ts @@ -1,24 +1,2 @@ -/** - * Process-unique client-side id counter. - * - * `useId()` returns the next value of a monotonic module-level counter — - * cheaper than `Date.now()` and, unlike a timestamp, collision-free. Use it - * for client-only ephemeral ids (list keys, generated handles). - * - * NOT for SSR / ARIA element ids derived from the component tree — those use - * soma's `createId`, which wraps Svelte's `$props.id()` for hydration-stable - * output. A global counter would desync between server and client renders. - * - * Lives in active-uix (not soma) so any UIX layer — soma, eidos, demos, - * apps — can mint ids without coupling to soma. Imported by subpath - * (`$active-uix/id`), mirroring `$active-uix/prefs`, so it never pulls the - * runtime barrel. The `soma-` prefix is the shared UIX id convention (same - * shape `createId` emits), not a marker of where this lives. - */ - -let counter = 0 - -export function useId(component = ''): string { - const id = ++counter - return component ? `soma-${component}-${id}` : `soma-${id}` -} +export { createId } from './create-id' +export { useId } from './use-id' diff --git a/src/uix/active-uix/id/use-id.ts b/src/uix/active-uix/id/use-id.ts new file mode 100644 index 000000000..b321a5884 --- /dev/null +++ b/src/uix/active-uix/id/use-id.ts @@ -0,0 +1,18 @@ +/** + * Process-unique client-side id counter. + * + * `useId()` returns the next value of a monotonic module-level counter — + * cheaper than `Date.now()` and, unlike a timestamp, collision-free. Use it + * for client-only ephemeral ids (list keys, generated handles). + * + * NOT for SSR / ARIA element ids derived from the component tree — those use + * `createId` (same module), which wraps Svelte's `$props.id()` for + * hydration-stable output. A global counter would desync server / client. + */ + +let counter = 0 + +export function useId(component = ''): string { + const id = ++counter + return component ? `soma-${component}-${id}` : `soma-${id}` +} diff --git a/src/uix/soma/COMPONENT_GUIDE.md b/src/uix/soma/COMPONENT_GUIDE.md index 974685e82..7622499ab 100644 --- a/src/uix/soma/COMPONENT_GUIDE.md +++ b/src/uix/soma/COMPONENT_GUIDE.md @@ -205,7 +205,7 @@ Do NOT redeclare field types in both `types.ts` and the Opts interface.