@threadlabs/looma 0.28.8 → 0.28.10

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.
@@ -0,0 +1,85 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ /** A destination supplied by the host application, such as a page or record. */
3
+ export interface LoomaLinkTarget {
4
+ id: string;
5
+ label: string;
6
+ detail?: string;
7
+ href: string;
8
+ }
9
+ /**
10
+ * Finds host records for a link without teaching the editor how they are stored.
11
+ * @ownership The host checks access and returns durable, openable href values.
12
+ * @failure A rejection leaves the existing document untouched and shows a retryable search error.
13
+ */
14
+ export type LoomaLinkSearch = (query: string) => Promise<LoomaLinkTarget[]>;
15
+ /**
16
+ * Describes a saved host link so a renamed record can show its current label.
17
+ * @ownership The host resolves identity and access; Looma keeps the saved href as is.
18
+ * @failure A rejection leaves the original href visible and editable.
19
+ */
20
+ export type LoomaLinkResolve = (href: string) => Promise<LoomaLinkTarget | null>;
21
+ /** The link form's state and the resolved target of the link at the caret. */
22
+ export interface LoomaLinkEditingState {
23
+ /** Where the form shows: nowhere, in the toolbar's popover, or in place of the link card. */
24
+ readonly surface: "none" | "popover" | "context";
25
+ /** The range the form links, and whether it was already a link when the form opened. */
26
+ readonly range: {
27
+ readonly from: number;
28
+ readonly to: number;
29
+ readonly existing: boolean;
30
+ } | null;
31
+ readonly mode: "target" | "url";
32
+ readonly query: string;
33
+ readonly href: string;
34
+ readonly text: string;
35
+ readonly textEditable: boolean;
36
+ readonly newTab: boolean;
37
+ readonly error: string;
38
+ readonly results: readonly LoomaLinkTarget[];
39
+ readonly searching: boolean;
40
+ readonly selected: LoomaLinkTarget | null;
41
+ /** What the link at the caret resolves to, for the link card. */
42
+ readonly current: LoomaLinkTarget | null;
43
+ }
44
+ export interface LoomaLinkEditingOptions {
45
+ editor: Editor;
46
+ /** Read on each use, so a host can change them while the editor runs. */
47
+ search: () => LoomaLinkSearch | null | undefined;
48
+ resolve: () => LoomaLinkResolve | null | undefined;
49
+ baseUrl: () => string;
50
+ }
51
+ /**
52
+ * The editor's link form as a state machine: what the form holds, how it applies to the
53
+ * document as the reader types, and the host's search and resolve calls.
54
+ *
55
+ * @ownership The host owns presentation: where the form shows, focus, and which selection it
56
+ * opens on. This owns the form's state and the link mark it writes.
57
+ * @lifecycle Listens to the editor's transactions until `destroy()`; results of a search or lookup
58
+ * that finish after a newer one, or after `destroy()`, are dropped.
59
+ */
60
+ export interface LoomaLinkEditing {
61
+ readonly state: LoomaLinkEditingState;
62
+ /** Calls `listener` after every state change; returns the unsubscribe function. */
63
+ subscribe(listener: () => void): () => void;
64
+ /** Opens the form on `from`–`to`, filled from the link there if there is one. */
65
+ open(from: number, to: number, surface: "popover" | "context"): void;
66
+ setDestination(value: string): void;
67
+ clear(): void;
68
+ choose(target: LoomaLinkTarget): void;
69
+ setNewTab(newTab: boolean): void;
70
+ setText(text: string): void;
71
+ /**
72
+ * Writes the form's link to its range without moving focus.
73
+ * @failure Returns false and leaves the document unchanged when the destination or text is
74
+ * missing or invalid; `reportError` also sets the form's error.
75
+ */
76
+ apply(reportError?: boolean): boolean;
77
+ close(): void;
78
+ /** Removes the link at the caret. */
79
+ remove(): void;
80
+ destroy(): void;
81
+ }
82
+ /** The status line above search results: progress, a hint, or an empty result. */
83
+ export declare function linkFormStatus(state: LoomaLinkEditingState): string;
84
+ export declare const LOOMA_LINK_EDITING_IDLE: LoomaLinkEditingState;
85
+ export declare function createLinkEditing(options: LoomaLinkEditingOptions): LoomaLinkEditing;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.28.8",
3
+ "version": "0.28.10",
4
4
  "type": "module",
5
5
  "description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
6
6
  "license": "MIT",
@@ -0,0 +1 @@
1
+ /* Generated by HTML Next 1.0.0-alpha.51. Do not edit. */
@@ -0,0 +1,16 @@
1
+ // Generated by HTML Next 1.0.0-alpha.51 for Vanilla DOM. Do not edit.
2
+ export interface UiEditorCodeLanguageEventMap {
3
+ language: CustomEvent<{ readonly value: string }>;
4
+ }
5
+ export interface UiEditorCodeLanguageElement extends HTMLDivElement {
6
+ addEventListener<K extends keyof UiEditorCodeLanguageEventMap>(type: K, listener: (this: UiEditorCodeLanguageElement, event: UiEditorCodeLanguageEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
7
+ removeEventListener<K extends keyof UiEditorCodeLanguageEventMap>(type: K, listener: (this: UiEditorCodeLanguageElement, event: UiEditorCodeLanguageEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
8
+ }
9
+ export interface UiEditorCodeLanguageProps {
10
+ languages?: readonly ({ readonly value: string; readonly label: string })[] | null;
11
+ value?: string | null;
12
+ attributes?: Readonly<Record<string, string | number | boolean | null | undefined>>;
13
+ children?: readonly (string | Node)[];
14
+ slots?: Readonly<Record<string, readonly (string | Node)[]>>;
15
+ }
16
+ export declare function createUiEditorCodeLanguage(props?: UiEditorCodeLanguageProps): UiEditorCodeLanguageElement;
@@ -0,0 +1,64 @@
1
+ // Generated by HTML Next 1.0.0-alpha.51 for Vanilla DOM. Do not edit.
2
+ import { attachGeneratedController, buildTemplate, KeyedList, readMember, toAttribute, toText, trackContainer, writeAttribute, dispatchDeclared, detailCheck, acceptProps, manageProps, checkList, checkObject, checkString } from "@nextwebwg/html-next/generated-runtime";
3
+ import * as controller from "../components/ui-editor-code-language/ui-editor-code-language.js";
4
+ import "../styles/ui-editor-code-language.css";
5
+
6
+ const T0 = ["",[],["ui-combobox",["label","Code language","label-visibility","sr-only","size","sm","filter","label"],2]];
7
+ const T1 = ["option",[],0];
8
+ let P0, P1;
9
+ const E = new Map();
10
+ const S = { n: [], t: [], f: import.meta.url, g: "ui-editor-code-language", d: { "language": [detailCheck(checkObject([["value", checkString, false]], false)), true, true, false] }, x: dispatchDeclared };
11
+ const D = { props: { "languages": { "required":false,"default":[], c: checkList(checkObject([["value", checkString, false], ["label", checkString, false]], false)), j: 1, m: ["l",["o",["value","s","label","s"]]] }, "value": { "required":false,"default":"auto", c: checkString, t: "string", j: 0, m: "s" } } };
12
+ const C = (host) => controller.default(host);
13
+
14
+ export function createUiEditorCodeLanguage(options = {}, html) {
15
+ const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
16
+ const element = document.createElement("div");
17
+ for (const [name, value] of Object.entries(attributes)) {
18
+ if (value === null || value === undefined || value === false) continue;
19
+ element.setAttribute(name, value === true ? "" : String(value));
20
+ }
21
+ element.setAttribute("data-component", "ui-editor-code-language");
22
+ element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
23
+ const v = [null, null];
24
+ const B = acceptProps(element, D, S.n, v, componentProps, [], html);
25
+ const m1 = (o, j, l) => {
26
+ const n = (P1 ??= buildTemplate(T1)).cloneNode(true);
27
+ const t0 = n.firstChild;
28
+ const r = { k: undefined, i: o, n, x: 0, y: 0, a1: t0, w: 0, v0: null, v1: "" };
29
+ p1(r, -1, E);
30
+ return r;
31
+ };
32
+ const p1 = (r, c, d) => {
33
+ const o = r.i;
34
+ if (c & 1073741824) {
35
+ r.w = 0;
36
+ const x0 = trackContainer(r, readMember(o, "value"));
37
+ const s0 = toAttribute(x0, "value");
38
+ if (s0 !== r.v0) writeAttribute(r.n, "value", r.v0 = s0);
39
+ const x1 = trackContainer(r, readMember(o, "label"));
40
+ const s1 = toText(x1);
41
+ if (s1 !== r.v1) r.a1.data = r.v1 = s1;
42
+ }
43
+ };
44
+ const p0 = (r, c, d) => {
45
+ if (c === -1) {
46
+ const x0 = true;
47
+ const s0 = toAttribute(x0, "disclosure");
48
+ if (s0 !== r.v0) writeAttribute(r.a0, "disclosure", r.v0 = s0);
49
+ }
50
+ if (c & 2) {
51
+ const x1 = v[1];
52
+ const s1 = toAttribute(x1, "value");
53
+ if (s1 !== r.v1) writeAttribute(r.a0, "value", r.v1 = s1);
54
+ }
55
+ if (c & 1073741825) r.L0.update(v[0], d, c);
56
+ };
57
+ const t0 = element.firstChild;
58
+ const t1 = t0.firstChild;
59
+ const R = { a0: t0, v0: null, v1: null, L0: new KeyedList(t1, t1.nextSibling, m1, p1, (o) => readMember(o, "value"), "language") };
60
+ const I = { B };
61
+ attachGeneratedController(element, S, v, ((c, d) => p0(R, c, d)), C, undefined, I);
62
+ manageProps(I);
63
+ return element;
64
+ }
package/vanilla/index.js CHANGED
@@ -20,6 +20,7 @@ export * from "./UiDialog.js";
20
20
  export * from "./UiDisclosure.js";
21
21
  export * from "./UiEditable.js";
22
22
  export * from "./UiEditorBlockActions.js";
23
+ export * from "./UiEditorCodeLanguage.js";
23
24
  export * from "./UiEditorImageToolbar.js";
24
25
  export * from "./UiEditorInsertTableGrid.js";
25
26
  export * from "./UiEditorLinkCard.js";
@@ -0,0 +1,44 @@
1
+ import type { PropType } from 'vue';
2
+ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
3
+ languages: {
4
+ type: PropType<readonly ({
5
+ readonly value: string;
6
+ readonly label: string;
7
+ })[] | null>;
8
+ default: () => never[];
9
+ };
10
+ value: {
11
+ type: PropType<string | null>;
12
+ default: string;
13
+ };
14
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ "update:value": (value: string) => any;
16
+ language: (event: CustomEvent<{
17
+ readonly value: string;
18
+ }>) => any;
19
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
20
+ languages: {
21
+ type: PropType<readonly ({
22
+ readonly value: string;
23
+ readonly label: string;
24
+ })[] | null>;
25
+ default: () => never[];
26
+ };
27
+ value: {
28
+ type: PropType<string | null>;
29
+ default: string;
30
+ };
31
+ }>> & Readonly<{
32
+ "onUpdate:value"?: ((value: string) => any) | undefined;
33
+ onLanguage?: ((event: CustomEvent<{
34
+ readonly value: string;
35
+ }>) => any) | undefined;
36
+ }>, {
37
+ value: string | null;
38
+ languages: readonly {
39
+ readonly value: string;
40
+ readonly label: string;
41
+ }[] | null;
42
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
43
+ declare const _default: typeof __VLS_export;
44
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import { t as UiEditorCodeLanguage_default } from "./chunks/UiEditorCodeLanguage.js";
2
+ export { UiEditorCodeLanguage_default as default };
@@ -0,0 +1,156 @@
1
+ <!-- Generated by HTML Next 1.0.0-alpha.51 for Vue 3.5. Do not edit. -->
2
+ <script setup lang="ts">
3
+ import { computed, getCurrentInstance, ref, watchSyncEffect } from 'vue'
4
+ import type { PropType } from 'vue'
5
+ import {
6
+ checkHydratedRoot,
7
+ createDispatch,
8
+ KeyedBoundary,
9
+ nativeAttrs,
10
+ uniqueKeys,
11
+ useComponentHost,
12
+ useReflectedProp,
13
+ } from './host'
14
+ import { checkedProp, propValidityState, vPropValidity } from './props'
15
+ import UiCombobox from './UiCombobox.vue'
16
+
17
+ defineOptions({ inheritAttrs: false })
18
+
19
+ const propValidityContract = {
20
+ props: {
21
+ languages: {
22
+ type: {
23
+ kind: 'list',
24
+ item: {
25
+ kind: 'object',
26
+ fields: [{ name: 'value', type: { kind: 'terminal', name: 'string' }, optional: false }, {
27
+ name: 'label',
28
+ type: { kind: 'terminal', name: 'string' },
29
+ optional: false,
30
+ }],
31
+ open: false,
32
+ },
33
+ },
34
+ required: false,
35
+ target: { attribute: 'languages' },
36
+ description:
37
+ 'The languages to offer, in order, each with its label; the editor lists Auto first and marks a saved language it cannot highlight.',
38
+ default: [],
39
+ },
40
+ value: {
41
+ type: { kind: 'terminal', name: 'string' },
42
+ required: false,
43
+ target: { attribute: 'value' },
44
+ description: 'The code block\'s language, or auto to detect it.',
45
+ default: 'auto',
46
+ },
47
+ },
48
+ } as const
49
+ const props = defineProps({
50
+ languages: {
51
+ type: null as unknown as PropType<
52
+ readonly ({ readonly value: string; readonly label: string })[] | null
53
+ >,
54
+ default: () => [],
55
+ },
56
+ value: { type: null as unknown as PropType<string | null>, default: 'auto' },
57
+ })
58
+ const acceptedProps: Record<string, unknown> = { languages: () => [], value: 'auto' }
59
+ const checkedProps = computed(() => ({
60
+ languages: checkedProp<readonly ({ readonly value: string; readonly label: string })[]>(
61
+ props['languages'],
62
+ {
63
+ kind: 'list',
64
+ item: {
65
+ kind: 'object',
66
+ fields: [{ name: 'value', type: { kind: 'terminal', name: 'string' }, optional: false }, {
67
+ name: 'label',
68
+ type: { kind: 'terminal', name: 'string' },
69
+ optional: false,
70
+ }],
71
+ open: false,
72
+ },
73
+ },
74
+ false,
75
+ 'languages',
76
+ acceptedProps,
77
+ ) as readonly ({ readonly value: string; readonly label: string })[],
78
+ value: checkedProp<string>(
79
+ props['value'],
80
+ { kind: 'terminal', name: 'string' },
81
+ false,
82
+ 'value',
83
+ acceptedProps,
84
+ ) as string,
85
+ }))
86
+ void checkedProps.value
87
+ watchSyncEffect(() => {
88
+ void checkedProps.value
89
+ })
90
+ const reflectedProp = useReflectedProp()
91
+ const hydrationInstance = getCurrentInstance()
92
+ const emit = defineEmits<{
93
+ 'update:value': [value: string]
94
+ language: [event: CustomEvent<{ readonly value: string }>]
95
+ }>()
96
+
97
+ const root = ref<HTMLElement | null>(null)
98
+ checkHydratedRoot('div', 'ui-editor-code-language')
99
+
100
+ const isLanguageDetail = (
101
+ detail: unknown,
102
+ ): boolean => (detail !== null && typeof detail === 'object' && !Array.isArray(detail)
103
+ && typeof (detail as Record<string, unknown>)['value'] === 'string'
104
+ && Object.keys(detail as object).every((key) => ['value'].includes(key)))
105
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
106
+ checks: {
107
+ language: isLanguageDetail,
108
+ },
109
+ modeled: ['value'],
110
+ })
111
+
112
+ useComponentHost(() => import('../components/ui-editor-code-language/ui-editor-code-language.js'), {
113
+ root,
114
+ dispatch,
115
+ controllerSource: {
116
+ specifier: '../components/ui-editor-code-language/ui-editor-code-language.js',
117
+ definition: './components/ui-editor-code-language/ui-editor-code-language.html',
118
+ },
119
+ props: checkedProps,
120
+ propInputs: (name: string) => {
121
+ const incoming = hydrationInstance?.vnode.props
122
+ const kebab = name.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase())
123
+ return incoming !== null && incoming !== undefined
124
+ ? (incoming[name] ?? incoming[kebab] ?? null)
125
+ : null
126
+ },
127
+ propNames: ['languages', 'value'],
128
+ propValidity: (name: string) =>
129
+ propValidityState({ contract: propValidityContract, values: { ...props } }, name),
130
+ })
131
+ </script>
132
+
133
+ <template>
134
+ <div
135
+ v-bind="nativeAttrs($attrs)"
136
+ v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
137
+ :data-languages="reflectedProp('languages', 'languages', checkedProps.languages, undefined, false)"
138
+ :data-value="reflectedProp('value', 'value', checkedProps.value, undefined, false)"
139
+ ref="root"
140
+ >
141
+ <UiCombobox
142
+ label="Code language"
143
+ label-visibility="sr-only"
144
+ size="sm"
145
+ filter="label"
146
+ :disclosure="true"
147
+ :value="checkedProps.value"
148
+ ><KeyedBoundary><option
149
+ v-for="language in uniqueKeys(checkedProps.languages, (language, index, loop) => language.value)"
150
+ :key="language.value"
151
+ :value="language.value"
152
+ >
153
+ {{ language.label }}
154
+ </option></KeyedBoundary></UiCombobox>
155
+ </div>
156
+ </template>
@@ -0,0 +1,163 @@
1
+ import { _ as uniqueKeys, i as checkHydratedRoot, n as KeyedBoundary, o as createDispatch, p as nativeAttrs, v as useComponentHost, y as useReflectedProp } from "./_plugin-vue_export-helper.js";
2
+ import { a as vPropValidity, n as checkedProp, r as propValidityState } from "./props.js";
3
+ import { t as UiCombobox_default } from "./UiCombobox.js";
4
+ import { Fragment, computed, createElementBlock, createVNode, defineComponent, getCurrentInstance, mergeProps, openBlock, ref, renderList, toDisplayString, unref, watchSyncEffect, withCtx, withDirectives } from "vue";
5
+ //#region .build/vue/UiEditorCodeLanguage.vue?vue&type=script&setup=true&lang.ts
6
+ var _hoisted_1 = ["data-languages", "data-value"];
7
+ var _hoisted_2 = ["value"];
8
+ //#endregion
9
+ //#region .build/vue/UiEditorCodeLanguage.vue
10
+ var UiEditorCodeLanguage_default = /* @__PURE__ */ defineComponent({
11
+ inheritAttrs: false,
12
+ __name: "UiEditorCodeLanguage",
13
+ props: {
14
+ languages: {
15
+ type: null,
16
+ default: () => []
17
+ },
18
+ value: {
19
+ type: null,
20
+ default: "auto"
21
+ }
22
+ },
23
+ emits: ["update:value", "language"],
24
+ setup(__props, { emit: __emit }) {
25
+ const propValidityContract = { props: {
26
+ languages: {
27
+ type: {
28
+ kind: "list",
29
+ item: {
30
+ kind: "object",
31
+ fields: [{
32
+ name: "value",
33
+ type: {
34
+ kind: "terminal",
35
+ name: "string"
36
+ },
37
+ optional: false
38
+ }, {
39
+ name: "label",
40
+ type: {
41
+ kind: "terminal",
42
+ name: "string"
43
+ },
44
+ optional: false
45
+ }],
46
+ open: false
47
+ }
48
+ },
49
+ required: false,
50
+ target: { attribute: "languages" },
51
+ description: "The languages to offer, in order, each with its label; the editor lists Auto first and marks a saved language it cannot highlight.",
52
+ default: []
53
+ },
54
+ value: {
55
+ type: {
56
+ kind: "terminal",
57
+ name: "string"
58
+ },
59
+ required: false,
60
+ target: { attribute: "value" },
61
+ description: "The code block's language, or auto to detect it.",
62
+ default: "auto"
63
+ }
64
+ } };
65
+ const props = __props;
66
+ const acceptedProps = {
67
+ languages: () => [],
68
+ value: "auto"
69
+ };
70
+ const checkedProps = computed(() => ({
71
+ languages: checkedProp(props["languages"], {
72
+ kind: "list",
73
+ item: {
74
+ kind: "object",
75
+ fields: [{
76
+ name: "value",
77
+ type: {
78
+ kind: "terminal",
79
+ name: "string"
80
+ },
81
+ optional: false
82
+ }, {
83
+ name: "label",
84
+ type: {
85
+ kind: "terminal",
86
+ name: "string"
87
+ },
88
+ optional: false
89
+ }],
90
+ open: false
91
+ }
92
+ }, false, "languages", acceptedProps),
93
+ value: checkedProp(props["value"], {
94
+ kind: "terminal",
95
+ name: "string"
96
+ }, false, "value", acceptedProps)
97
+ }));
98
+ checkedProps.value;
99
+ watchSyncEffect(() => {
100
+ checkedProps.value;
101
+ });
102
+ const reflectedProp = useReflectedProp();
103
+ const hydrationInstance = getCurrentInstance();
104
+ const emit = __emit;
105
+ const root = ref(null);
106
+ checkHydratedRoot("div", "ui-editor-code-language");
107
+ const isLanguageDetail = (detail) => detail !== null && typeof detail === "object" && !Array.isArray(detail) && typeof detail["value"] === "string" && Object.keys(detail).every((key) => ["value"].includes(key));
108
+ const dispatch = createDispatch(root, emit, {
109
+ checks: { language: isLanguageDetail },
110
+ modeled: ["value"]
111
+ });
112
+ useComponentHost(() => import("@threadlabs/looma/components/ui-editor-code-language/ui-editor-code-language.js"), {
113
+ root,
114
+ dispatch,
115
+ controllerSource: {
116
+ specifier: "../components/ui-editor-code-language/ui-editor-code-language.js",
117
+ definition: "./components/ui-editor-code-language/ui-editor-code-language.html"
118
+ },
119
+ props: checkedProps,
120
+ propInputs: (name) => {
121
+ const incoming = hydrationInstance?.vnode.props;
122
+ const kebab = name.replace(/[A-Z]/g, (letter) => "-" + letter.toLowerCase());
123
+ return incoming !== null && incoming !== void 0 ? incoming[name] ?? incoming[kebab] ?? null : null;
124
+ },
125
+ propNames: ["languages", "value"],
126
+ propValidity: (name) => propValidityState({
127
+ contract: propValidityContract,
128
+ values: { ...props }
129
+ }, name)
130
+ });
131
+ return (_ctx, _cache) => {
132
+ return withDirectives((openBlock(), createElementBlock("div", mergeProps(unref(nativeAttrs)(_ctx.$attrs), {
133
+ "data-languages": unref(reflectedProp)("languages", "languages", checkedProps.value.languages, void 0, false),
134
+ "data-value": unref(reflectedProp)("value", "value", checkedProps.value.value, void 0, false),
135
+ ref_key: "root",
136
+ ref: root
137
+ }), [createVNode(UiCombobox_default, {
138
+ label: "Code language",
139
+ "label-visibility": "sr-only",
140
+ size: "sm",
141
+ filter: "label",
142
+ disclosure: true,
143
+ value: checkedProps.value.value
144
+ }, {
145
+ default: withCtx(() => [createVNode(unref(KeyedBoundary), null, {
146
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(uniqueKeys)(checkedProps.value.languages, (language, index, loop) => language.value), (language) => {
147
+ return openBlock(), createElementBlock("option", {
148
+ key: language.value,
149
+ value: language.value
150
+ }, toDisplayString(language.label), 9, _hoisted_2);
151
+ }), 128))]),
152
+ _: 1
153
+ })]),
154
+ _: 1
155
+ }, 8, ["value"])], 16, _hoisted_1)), [[unref(vPropValidity), {
156
+ contract: propValidityContract,
157
+ values: { ...props }
158
+ }]]);
159
+ };
160
+ }
161
+ });
162
+ //#endregion
163
+ export { UiEditorCodeLanguage_default as t };
@@ -4,6 +4,7 @@ import { type AnyExtension, type Editor, type JSONContent } from "@tiptap/core";
4
4
  import { type PropType, type VNode } from "vue";
5
5
  import { type LoomaSlashCommand, type LoomaMentionItem, type LoomaMentionProvider, type LoomaCodeLanguages } from "@threadlabs/looma/editor";
6
6
  import { type LoomaImageActivationDetail, type LoomaImageAttributeResolver, type LoomaImageDescriptor, type LoomaImageRenditionErrorDetail } from "../../editor/image-delivery.js";
7
+ import { type LoomaLinkResolve, type LoomaLinkSearch } from "../../editor/link-editing.js";
7
8
  /**
8
9
  * Host upload result normalized into the editor's durable image descriptor.
9
10
  * `url` becomes the stored `src`; optional dimensions preserve layout before
@@ -62,25 +63,7 @@ export interface LoomaEditorSelectionActionDetail {
62
63
  * fresh defaults and invokes this factory when the inventory prop changes.
63
64
  */
64
65
  export type LoomaEditorSlashCommands = LoomaSlashCommand[] | ((defaults: LoomaSlashCommand[]) => LoomaSlashCommand[]);
65
- /** A destination supplied by the host application, such as a page or record. */
66
- export interface LoomaLinkTarget {
67
- id: string;
68
- label: string;
69
- detail?: string;
70
- href: string;
71
- }
72
- /**
73
- * Finds host records for a link without teaching the editor how they are stored.
74
- * @ownership The host checks access and returns durable, openable href values.
75
- * @failure A rejection leaves the existing document untouched and shows a retryable search error.
76
- */
77
- export type LoomaLinkSearch = (query: string) => Promise<LoomaLinkTarget[]>;
78
- /**
79
- * Describes a saved host link so a renamed record can show its current label.
80
- * @ownership The host resolves identity and access; Looma keeps the saved href as is.
81
- * @failure A rejection leaves the original href visible and editable.
82
- */
83
- export type LoomaLinkResolve = (href: string) => Promise<LoomaLinkTarget | null>;
66
+ export type { LoomaLinkResolve, LoomaLinkSearch, LoomaLinkTarget } from "../../editor/link-editing.js";
84
67
  /**
85
68
  * Turnkey Vue editor that composes Looma's framework-neutral Tiptap extensions
86
69
  * with declarative menus, image delivery, and table interaction chrome.