@threadlabs/looma 0.23.21 → 0.23.22

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.
Files changed (45) hide show
  1. package/components/shared/overlay.js +1 -1
  2. package/components/ui-image/ui-image.html +177 -0
  3. package/components/ui-image/ui-image.js +107 -0
  4. package/components/ui-menu/ui-menu.js +1 -1
  5. package/components/ui-popover/ui-popover.js +4 -1
  6. package/components/ui-separator/ui-separator.html +18 -0
  7. package/dist/index.js +24 -23
  8. package/editor/chunks/extensions.js +633 -20
  9. package/editor/extensions/block-selection.d.ts +6 -0
  10. package/editor/extensions/expand.d.ts +31 -0
  11. package/editor/extensions/image.d.ts +12 -0
  12. package/editor/extensions/index.d.ts +4 -1
  13. package/editor/extensions/index.js +2 -2
  14. package/editor/extensions/preset.d.ts +8 -0
  15. package/editor/extensions/slash-command.d.ts +31 -3
  16. package/editor/extensions/table-of-contents.d.ts +58 -0
  17. package/editor/index.js +2 -2
  18. package/package.json +1 -1
  19. package/styles/ui-image.css +153 -0
  20. package/styles/ui-separator.css +16 -0
  21. package/vanilla/UiImage.d.ts +21 -0
  22. package/vanilla/UiImage.js +84 -0
  23. package/vanilla/UiSeparator.d.ts +2 -0
  24. package/vanilla/UiSeparator.js +10 -2
  25. package/vanilla/index.js +1 -0
  26. package/vue/UiImage.d.ts +100 -0
  27. package/vue/UiImage.js +2 -0
  28. package/vue/UiImage.vue +463 -0
  29. package/vue/UiSeparator.d.ts +18 -0
  30. package/vue/UiSeparator.vue +66 -1
  31. package/vue/UiSidebar.d.ts +1 -1
  32. package/vue/chunks/UiImage.js +313 -0
  33. package/vue/chunks/UiSeparator.js +79 -22
  34. package/vue/components.css +169 -9
  35. package/vue/editor/LoomaEditor.d.ts +19 -2
  36. package/vue/editor/divider.d.ts +6 -0
  37. package/vue/editor/expand.d.ts +7 -0
  38. package/vue/editor/image-controls.d.ts +19 -0
  39. package/vue/editor/image-delivery.d.ts +2 -2
  40. package/vue/editor/image.d.ts +7 -0
  41. package/vue/editor/index.d.ts +1 -1
  42. package/vue/editor/index.js +1188 -52
  43. package/vue/editor/table-of-contents.d.ts +7 -0
  44. package/vue/index.d.ts +1 -0
  45. package/vue/index.js +2 -1
@@ -101,9 +101,9 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
101
101
  "onUpdate:width"?: ((value: number) => any) | undefined;
102
102
  }>, {
103
103
  width: number | null;
104
+ resizable: boolean | null;
104
105
  breakpoint: "sm" | "md" | "lg" | null;
105
106
  collapsed: boolean | null;
106
- resizable: boolean | null;
107
107
  side: "start" | "end" | null;
108
108
  maxWidth: number | null;
109
109
  minWidth: number | null;
@@ -0,0 +1,313 @@
1
+ import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper.js";
2
+ import { r as useComponentHost, t as createDispatch } from "./host.js";
3
+ import { i as vPropValidity, n as propValidityState, t as checkedProp } from "./props.js";
4
+ import { computed, createElementBlock, createElementVNode, defineComponent, getCurrentInstance, mergeProps, openBlock, ref, renderSlot, unref, useTemplateRef, watchSyncEffect, withDirectives } from "vue";
5
+ //#region .build/vue/UiImage.vue?vue&type=script&setup=true&lang.ts
6
+ var _hoisted_1 = [
7
+ "data-alt",
8
+ "data-height",
9
+ "data-placement",
10
+ "data-resizable",
11
+ "data-selected",
12
+ "data-src",
13
+ "data-width",
14
+ "data-ui-image-state"
15
+ ];
16
+ var _hoisted_2 = {
17
+ class: "frame",
18
+ ref: "frame"
19
+ };
20
+ var _hoisted_3 = [
21
+ "src",
22
+ "alt",
23
+ "width",
24
+ "height"
25
+ ];
26
+ var _hoisted_4 = ["hidden"];
27
+ //#endregion
28
+ //#region .build/vue/UiImage.vue
29
+ var UiImage_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
30
+ inheritAttrs: false,
31
+ __name: "UiImage",
32
+ props: {
33
+ alt: {
34
+ type: null,
35
+ default: ""
36
+ },
37
+ height: {
38
+ type: null,
39
+ default: null
40
+ },
41
+ placement: {
42
+ type: null,
43
+ default: "block"
44
+ },
45
+ resizable: {
46
+ type: null,
47
+ default: false
48
+ },
49
+ selected: {
50
+ type: null,
51
+ default: false
52
+ },
53
+ src: {
54
+ type: null,
55
+ default: ""
56
+ },
57
+ width: {
58
+ type: null,
59
+ default: null
60
+ }
61
+ },
62
+ emits: [
63
+ "update:height",
64
+ "update:width",
65
+ "resize"
66
+ ],
67
+ setup(__props, { emit: __emit }) {
68
+ const propValidityContract = { props: {
69
+ alt: {
70
+ type: {
71
+ kind: "terminal",
72
+ name: "string"
73
+ },
74
+ required: false,
75
+ target: { attribute: "alt" },
76
+ description: "A text alternative for the image.",
77
+ default: ""
78
+ },
79
+ height: {
80
+ type: {
81
+ kind: "terminal",
82
+ name: "integer"
83
+ },
84
+ required: false,
85
+ target: { attribute: "height" },
86
+ description: "Image height in CSS pixels; resizing preserves the intrinsic aspect ratio."
87
+ },
88
+ placement: {
89
+ type: {
90
+ kind: "terminal",
91
+ name: "keyword"
92
+ },
93
+ required: false,
94
+ target: { attribute: "placement" },
95
+ description: "Block keeps text below; center centers the image; wrap-left and wrap-right let following text flow beside it.",
96
+ values: [
97
+ "block",
98
+ "center",
99
+ "wrap-left",
100
+ "wrap-right"
101
+ ],
102
+ default: "block"
103
+ },
104
+ resizable: {
105
+ type: {
106
+ kind: "terminal",
107
+ name: "boolean"
108
+ },
109
+ required: false,
110
+ target: { attribute: "resizable" },
111
+ description: "Shows four corner handles while selected. Drag to resize, or focus a handle and use arrow keys; Shift uses a larger increment.",
112
+ default: false
113
+ },
114
+ selected: {
115
+ type: {
116
+ kind: "terminal",
117
+ name: "boolean"
118
+ },
119
+ required: false,
120
+ target: { attribute: "selected" },
121
+ description: "Outlines the media as the current selection.",
122
+ default: false
123
+ },
124
+ src: {
125
+ type: {
126
+ kind: "terminal",
127
+ name: "string"
128
+ },
129
+ required: false,
130
+ target: { attribute: "src" },
131
+ description: "The image source, used by the default media.",
132
+ default: ""
133
+ },
134
+ width: {
135
+ type: {
136
+ kind: "terminal",
137
+ name: "integer"
138
+ },
139
+ required: false,
140
+ target: { attribute: "width" },
141
+ description: "Image width in CSS pixels; omitted uses intrinsic size in block/center placement or responsive sizing when wrapping."
142
+ }
143
+ } };
144
+ const props = __props;
145
+ const acceptedProps = {
146
+ alt: "",
147
+ height: null,
148
+ placement: "block",
149
+ resizable: false,
150
+ selected: false,
151
+ src: "",
152
+ width: null
153
+ };
154
+ const checkedProps = computed(() => ({
155
+ alt: checkedProp(props["alt"], {
156
+ kind: "terminal",
157
+ name: "string"
158
+ }, false, "alt", acceptedProps),
159
+ height: checkedProp(props["height"], {
160
+ kind: "terminal",
161
+ name: "integer"
162
+ }, false, "height", acceptedProps),
163
+ placement: checkedProp(props["placement"], {
164
+ kind: "terminal",
165
+ name: "keyword"
166
+ }, false, "placement", acceptedProps),
167
+ resizable: checkedProp(props["resizable"], {
168
+ kind: "terminal",
169
+ name: "boolean"
170
+ }, false, "resizable", acceptedProps),
171
+ selected: checkedProp(props["selected"], {
172
+ kind: "terminal",
173
+ name: "boolean"
174
+ }, false, "selected", acceptedProps),
175
+ src: checkedProp(props["src"], {
176
+ kind: "terminal",
177
+ name: "string"
178
+ }, false, "src", acceptedProps),
179
+ width: checkedProp(props["width"], {
180
+ kind: "terminal",
181
+ name: "integer"
182
+ }, false, "width", acceptedProps)
183
+ }));
184
+ checkedProps.value;
185
+ watchSyncEffect(() => {
186
+ checkedProps.value;
187
+ });
188
+ function nativeAttrs(attrs) {
189
+ const names = Object.keys(attrs);
190
+ if (!names.some((name) => Object.hasOwn(Object.prototype, name))) return attrs;
191
+ return Object.fromEntries(names.map((name) => [Object.hasOwn(Object.prototype, name) ? name === "__proto__" ? "__Proto__" : name[0].toUpperCase() + name.slice(1) : name, attrs[name]]));
192
+ }
193
+ const componentInstance = getCurrentInstance();
194
+ function reflectedProp(name, kebab, value, fallback, bound, separator) {
195
+ const incoming = componentInstance?.vnode.props;
196
+ if (!bound && (incoming === null || incoming === void 0 || !Object.hasOwn(incoming, name) && !Object.hasOwn(incoming, kebab))) return fallback;
197
+ if (value === null || value === void 0) return void 0;
198
+ return Array.isArray(value) && separator !== void 0 ? value.join(separator) : typeof value === "object" ? JSON.stringify(value) : String(value);
199
+ }
200
+ const hydrationInstance = getCurrentInstance();
201
+ const emit = __emit;
202
+ const root = ref(null);
203
+ const frameElement = useTemplateRef("frame");
204
+ const hydrationNode = hydrationInstance?.vnode.el;
205
+ if (typeof window !== "undefined" && hydrationNode != null && (!(hydrationNode instanceof Element) || hydrationNode.localName !== "figure")) throw Object.assign(/* @__PURE__ */ new Error("HR005: Server markup for <ui-image> has an incompatible root."), {
206
+ name: "HtmlDiagnosticError",
207
+ diagnostic: Object.freeze({
208
+ code: "HR005",
209
+ message: "Server markup for <ui-image> has an incompatible root."
210
+ })
211
+ });
212
+ /** The values the styles' :host-state() rules test. */
213
+ const hostState = computed(() => [
214
+ checkedProps.value.placement && "placement",
215
+ checkedProps.value.placement != null && `placement=${encodeURIComponent(checkedProps.value.placement)}`,
216
+ checkedProps.value.selected && "selected"
217
+ ].filter(Boolean).join(" "));
218
+ const isResizeDetail = (detail) => detail !== null && typeof detail === "object" && !Array.isArray(detail) && Number.isInteger(detail["width"]) && Number.isInteger(detail["height"]) && (detail["phase"] === "preview" || detail["phase"] === "commit" || detail["phase"] === "cancel") && (detail["trigger"] === "pointer" || detail["trigger"] === "keyboard") && Object.keys(detail).every((key) => [
219
+ "width",
220
+ "height",
221
+ "phase",
222
+ "trigger"
223
+ ].includes(key));
224
+ const dispatch = createDispatch(root, emit, {
225
+ checks: { resize: isResizeDetail },
226
+ modeled: ["height", "width"]
227
+ });
228
+ useComponentHost(() => import("@threadlabs/looma/components/ui-image/ui-image.js"), {
229
+ root,
230
+ dispatch,
231
+ controllerSource: {
232
+ specifier: "../components/ui-image/ui-image.js",
233
+ definition: "./components/ui-image/ui-image.html"
234
+ },
235
+ props: checkedProps,
236
+ propInputs: (name) => {
237
+ const incoming = hydrationInstance?.vnode.props;
238
+ const kebab = name.replace(/[A-Z]/g, (letter) => "-" + letter.toLowerCase());
239
+ return incoming !== null && incoming !== void 0 ? incoming[name] ?? incoming[kebab] ?? null : null;
240
+ },
241
+ propNames: [
242
+ "alt",
243
+ "height",
244
+ "placement",
245
+ "resizable",
246
+ "selected",
247
+ "src",
248
+ "width"
249
+ ],
250
+ propValidity: (name) => propValidityState({
251
+ contract: propValidityContract,
252
+ values: { ...props }
253
+ }, name),
254
+ refs: { frame: frameElement }
255
+ });
256
+ return (_ctx, _cache) => {
257
+ return withDirectives((openBlock(), createElementBlock("figure", mergeProps({ "data-component": "ui-image" }, nativeAttrs(_ctx.$attrs), {
258
+ "data-alt": reflectedProp("alt", "alt", checkedProps.value.alt, void 0, false),
259
+ "data-height": reflectedProp("height", "height", checkedProps.value.height, void 0, false),
260
+ "data-placement": reflectedProp("placement", "placement", checkedProps.value.placement, void 0, false),
261
+ "data-resizable": reflectedProp("resizable", "resizable", checkedProps.value.resizable, void 0, false),
262
+ "data-selected": reflectedProp("selected", "selected", checkedProps.value.selected, void 0, false),
263
+ "data-src": reflectedProp("src", "src", checkedProps.value.src, void 0, false),
264
+ "data-width": reflectedProp("width", "width", checkedProps.value.width, void 0, false),
265
+ "data-ui-image-state": hostState.value || void 0,
266
+ ref_key: "root",
267
+ ref: root
268
+ }), [createElementVNode("div", _hoisted_2, [
269
+ renderSlot(_ctx.$slots, "media", {}, () => [createElementVNode("img", {
270
+ src: checkedProps.value.src ?? void 0,
271
+ alt: checkedProps.value.alt ?? void 0,
272
+ width: checkedProps.value.width ?? void 0,
273
+ height: checkedProps.value.height ?? void 0
274
+ }, null, 8, _hoisted_3)]),
275
+ createElementVNode("div", {
276
+ class: "handles",
277
+ hidden: !(checkedProps.value.selected && checkedProps.value.resizable)
278
+ }, [..._cache[0] || (_cache[0] = [
279
+ createElementVNode("button", {
280
+ type: "button",
281
+ class: "handle",
282
+ "data-corner": "top-left",
283
+ "aria-label": "Resize image from top left"
284
+ }, null, -1),
285
+ createElementVNode("button", {
286
+ type: "button",
287
+ class: "handle",
288
+ "data-corner": "top-right",
289
+ "aria-label": "Resize image from top right"
290
+ }, null, -1),
291
+ createElementVNode("button", {
292
+ type: "button",
293
+ class: "handle",
294
+ "data-corner": "bottom-left",
295
+ "aria-label": "Resize image from bottom left"
296
+ }, null, -1),
297
+ createElementVNode("button", {
298
+ type: "button",
299
+ class: "handle",
300
+ "data-corner": "bottom-right",
301
+ "aria-label": "Resize image from bottom right"
302
+ }, null, -1)
303
+ ])], 8, _hoisted_4),
304
+ renderSlot(_ctx.$slots, "controls")
305
+ ], 512)], 16, _hoisted_1)), [[unref(vPropValidity), {
306
+ contract: propValidityContract,
307
+ values: { ...props }
308
+ }]]);
309
+ };
310
+ }
311
+ }), [["__scopeId", "data-v-2895fbac"]]);
312
+ //#endregion
313
+ export { UiImage_default as t };
@@ -2,34 +2,86 @@ import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-hel
2
2
  import { i as vPropValidity, t as checkedProp } from "./props.js";
3
3
  import { computed, createElementBlock, defineComponent, getCurrentInstance, mergeProps, openBlock, unref, watchSyncEffect, withDirectives } from "vue";
4
4
  //#region .build/vue/UiSeparator.vue?vue&type=script&setup=true&lang.ts
5
- var _hoisted_1 = ["aria-orientation", "data-orientation"];
5
+ var _hoisted_1 = [
6
+ "aria-orientation",
7
+ "data-orientation",
8
+ "data-selectable",
9
+ "data-selected",
10
+ "data-ui-separator-state"
11
+ ];
6
12
  //#endregion
7
13
  //#region .build/vue/UiSeparator.vue
8
14
  var UiSeparator_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
9
15
  inheritAttrs: false,
10
16
  __name: "UiSeparator",
11
- props: { orientation: {
12
- type: null,
13
- default: "horizontal"
14
- } },
17
+ props: {
18
+ orientation: {
19
+ type: null,
20
+ default: "horizontal"
21
+ },
22
+ selectable: {
23
+ type: null,
24
+ default: false
25
+ },
26
+ selected: {
27
+ type: null,
28
+ default: false
29
+ }
30
+ },
15
31
  setup(__props) {
16
- const propValidityContract = { props: { orientation: {
17
- type: {
18
- kind: "terminal",
19
- name: "keyword"
32
+ const propValidityContract = { props: {
33
+ orientation: {
34
+ type: {
35
+ kind: "terminal",
36
+ name: "keyword"
37
+ },
38
+ required: false,
39
+ target: { attribute: "aria-orientation" },
40
+ description: "Whether the separator divides stacked content (horizontal) or inline content (vertical).",
41
+ values: ["horizontal", "vertical"],
42
+ default: "horizontal"
20
43
  },
21
- required: false,
22
- target: { attribute: "aria-orientation" },
23
- description: "Whether the separator divides stacked content (horizontal) or inline content (vertical).",
24
- values: ["horizontal", "vertical"],
25
- default: "horizontal"
26
- } } };
44
+ selectable: {
45
+ type: {
46
+ kind: "terminal",
47
+ name: "boolean"
48
+ },
49
+ required: false,
50
+ target: { attribute: "selectable" },
51
+ description: "Gives a document divider a pointer-sized hit area. The editor owns selection and deletion.",
52
+ default: false
53
+ },
54
+ selected: {
55
+ type: {
56
+ kind: "terminal",
57
+ name: "boolean"
58
+ },
59
+ required: false,
60
+ target: { attribute: "selected" },
61
+ description: "Shows the selected document divider. Selection does not change separator semantics.",
62
+ default: false
63
+ }
64
+ } };
27
65
  const props = __props;
28
- const acceptedProps = { orientation: "horizontal" };
29
- const checkedProps = computed(() => ({ orientation: checkedProp(props["orientation"], {
30
- kind: "terminal",
31
- name: "keyword"
32
- }, false, "orientation", acceptedProps) }));
66
+ const acceptedProps = {
67
+ orientation: "horizontal",
68
+ selectable: false,
69
+ selected: false
70
+ };
71
+ const checkedProps = computed(() => ({
72
+ orientation: checkedProp(props["orientation"], {
73
+ kind: "terminal",
74
+ name: "keyword"
75
+ }, false, "orientation", acceptedProps),
76
+ selectable: checkedProp(props["selectable"], {
77
+ kind: "terminal",
78
+ name: "boolean"
79
+ }, false, "selectable", acceptedProps),
80
+ selected: checkedProp(props["selected"], {
81
+ kind: "terminal",
82
+ name: "boolean"
83
+ }, false, "selected", acceptedProps)
84
+ }));
33
85
  checkedProps.value;
34
86
  watchSyncEffect(() => {
35
87
  checkedProps.value;
@@ -54,16 +106,21 @@ var UiSeparator_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__
54
106
  message: "Server markup for <ui-separator> has an incompatible root."
55
107
  })
56
108
  });
109
+ /** The values the styles' :host-state() rules test. */
110
+ const hostState = computed(() => [checkedProps.value.selectable && "selectable", checkedProps.value.selected && "selected"].filter(Boolean).join(" "));
57
111
  return (_ctx, _cache) => {
58
112
  return withDirectives((openBlock(), createElementBlock("hr", mergeProps({ "data-component": "ui-separator" }, nativeAttrs(_ctx.$attrs), {
59
113
  "aria-orientation": checkedProps.value.orientation ?? void 0,
60
- "data-orientation": reflectedProp("orientation", "orientation", checkedProps.value.orientation, void 0, false)
114
+ "data-orientation": reflectedProp("orientation", "orientation", checkedProps.value.orientation, void 0, false),
115
+ "data-selectable": reflectedProp("selectable", "selectable", checkedProps.value.selectable, void 0, false),
116
+ "data-selected": reflectedProp("selected", "selected", checkedProps.value.selected, void 0, false),
117
+ "data-ui-separator-state": hostState.value || void 0
61
118
  }), null, 16, _hoisted_1)), [[unref(vPropValidity), {
62
119
  contract: propValidityContract,
63
120
  values: { ...props }
64
121
  }]]);
65
122
  };
66
123
  }
67
- }), [["__scopeId", "data-v-5289daff"]]);
124
+ }), [["__scopeId", "data-v-7451a37c"]]);
68
125
  //#endregion
69
126
  export { UiSeparator_default as t };
@@ -4789,6 +4789,156 @@ svg[data-v-539c5c85-s] {
4789
4789
  display: none;
4790
4790
  }
4791
4791
 
4792
+ [data-component~="ui-image"][data-v-2895fbac] {
4793
+ display: flex;
4794
+ justify-content: flex-start;
4795
+ box-sizing: border-box;
4796
+ max-inline-size: 100%;
4797
+ min-inline-size: 0;
4798
+ margin: 0;
4799
+ padding: var(--ui-space-3) 0;
4800
+ }
4801
+ [data-component~="ui-image"][data-ui-image-state~="placement=center"][data-v-2895fbac] {
4802
+ justify-content: center;
4803
+ }
4804
+ [data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"][data-v-2895fbac] {
4805
+ float: left;
4806
+ padding-inline-end: var(--ui-space-4);
4807
+ }
4808
+ [data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"][data-v-2895fbac] {
4809
+ float: right;
4810
+ padding-inline-start: var(--ui-space-4);
4811
+ }
4812
+ [data-component~="ui-image"][data-v-2895fbac]:is([data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"], [data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"]) {
4813
+ inline-size: calc(var(--_ui-image-width, calc(100% / 3)) + var(--ui-space-4));
4814
+ }
4815
+ [data-component~="ui-image"]:is([data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"], [data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"])
4816
+ .frame[data-v-2895fbac] {
4817
+ inline-size: 100%;
4818
+ }
4819
+ [data-component~="ui-image"]:is([data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"], [data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"])
4820
+ .frame
4821
+ img[data-v-2895fbac],
4822
+ [data-component~="ui-image"]:is([data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"], [data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"])
4823
+ .frame
4824
+ img[data-v-2895fbac-s] {
4825
+ inline-size: 100%;
4826
+ }
4827
+ .frame[data-v-2895fbac] {
4828
+ position: relative;
4829
+ flex: 0 1 auto;
4830
+ inline-size: var(--_ui-image-width, fit-content);
4831
+ max-inline-size: 100%;
4832
+ min-inline-size: 0;
4833
+ align-self: flex-start;
4834
+ border-radius: var(--ui-radius-md);
4835
+ }
4836
+ .frame img[data-v-2895fbac], .frame img[data-v-2895fbac-s] {
4837
+ display: block;
4838
+ max-inline-size: 100%;
4839
+ block-size: auto;
4840
+ margin: 0;
4841
+ border-radius: inherit;
4842
+ }
4843
+ [data-component~="ui-image"][data-resizing] .frame img[data-v-2895fbac],
4844
+ [data-component~="ui-image"][data-resizing] .frame img[data-v-2895fbac-s] {
4845
+ inline-size: 100%;
4846
+ }
4847
+ [data-component~="ui-image"][data-ui-image-state~="selected"] .frame[data-v-2895fbac] {
4848
+ outline: var(--ui-focus-width) solid var(--ui-focus-ring);
4849
+ outline-offset: var(--ui-border-width);
4850
+ }
4851
+ .handle[data-v-2895fbac] {
4852
+ position: absolute;
4853
+ z-index: 1;
4854
+ inline-size: 24px;
4855
+ block-size: 24px;
4856
+ padding: 0;
4857
+ border: 0;
4858
+ background: transparent;
4859
+ touch-action: none;
4860
+ }
4861
+ .handle[data-v-2895fbac]::after {
4862
+ content: "";
4863
+ position: absolute;
4864
+ inset: 8px;
4865
+ background: var(--ui-surface);
4866
+ border: var(--ui-border-width) solid var(--ui-focus-ring);
4867
+ border-radius: var(--ui-radius-sm);
4868
+ }
4869
+ .handle[data-v-2895fbac]:focus-visible {
4870
+ outline: var(--ui-focus-width) solid var(--ui-focus-ring);
4871
+ border-radius: var(--ui-radius-sm);
4872
+ }
4873
+ .handle[data-corner="top-left"][data-v-2895fbac] {
4874
+ top: -12px;
4875
+ left: -12px;
4876
+ cursor: nwse-resize;
4877
+ }
4878
+ .handle[data-corner="top-right"][data-v-2895fbac] {
4879
+ top: -12px;
4880
+ right: -12px;
4881
+ cursor: nesw-resize;
4882
+ }
4883
+ .handle[data-corner="bottom-left"][data-v-2895fbac] {
4884
+ bottom: -12px;
4885
+ left: -12px;
4886
+ cursor: nesw-resize;
4887
+ }
4888
+ .handle[data-corner="bottom-right"][data-v-2895fbac] {
4889
+ bottom: -12px;
4890
+ right: -12px;
4891
+ cursor: nwse-resize;
4892
+ }
4893
+ .handles[hidden][data-v-2895fbac], [data-component~="ui-image"][hidden][data-v-2895fbac] {
4894
+ display: none;
4895
+ }
4896
+ @media (max-width: 767px) {
4897
+ [data-component~="ui-image"][data-v-2895fbac]:is([data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"], [data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"]) {
4898
+ float: none;
4899
+ inline-size: 100%;
4900
+ padding-inline: 0;
4901
+ }
4902
+ [data-component~="ui-image"]:is([data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"], [data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"])
4903
+ .handles[data-v-2895fbac] {
4904
+ display: none;
4905
+ }
4906
+ }
4907
+ @media (pointer: coarse) {
4908
+ .handle[data-v-2895fbac] {
4909
+ inline-size: 44px;
4910
+ block-size: 44px;
4911
+ }
4912
+ .handle[data-v-2895fbac]::after {
4913
+ inset: 18px;
4914
+ }
4915
+ .handle[data-corner="top-left"][data-v-2895fbac] {
4916
+ top: -22px;
4917
+ left: -22px;
4918
+ }
4919
+ .handle[data-corner="top-right"][data-v-2895fbac] {
4920
+ top: -22px;
4921
+ right: -22px;
4922
+ }
4923
+ .handle[data-corner="bottom-left"][data-v-2895fbac] {
4924
+ bottom: -22px;
4925
+ left: -22px;
4926
+ }
4927
+ .handle[data-corner="bottom-right"][data-v-2895fbac] {
4928
+ bottom: -22px;
4929
+ right: -22px;
4930
+ }
4931
+ }
4932
+ @media (forced-colors: active) {
4933
+ [data-component~="ui-image"][data-ui-image-state~="selected"] .frame[data-v-2895fbac], .handle[data-v-2895fbac]:focus-visible {
4934
+ outline-color: Highlight;
4935
+ }
4936
+ .handle[data-v-2895fbac]::after {
4937
+ border-color: Highlight;
4938
+ background: Canvas;
4939
+ }
4940
+ }
4941
+
4792
4942
  /* This component's hooks style the element they are set on, and never a nested one. An Input
4793
4943
  Group sets --_ui-default-input-* for the input inside it, below the input's own hooks. */
4794
4944
  @property --ui-input-border {
@@ -7033,7 +7183,7 @@ dialog[data-v-d317023c] {
7033
7183
  }
7034
7184
 
7035
7185
  /* The root is the hr, so the rules name :host; a bare hr matches only a descendant. */
7036
- [data-component~="ui-separator"][data-v-5289daff] {
7186
+ [data-component~="ui-separator"][data-v-7451a37c] {
7037
7187
  box-sizing: border-box;
7038
7188
  align-self: stretch;
7039
7189
  margin: 0;
@@ -7041,12 +7191,29 @@ dialog[data-v-d317023c] {
7041
7191
  border-block-start: var(--ui-border-width) solid
7042
7192
  var(--ui-separator-color, var(--ui-border-divider));
7043
7193
  }
7044
- [data-component~="ui-separator"][aria-orientation="vertical"][data-v-5289daff] {
7194
+ [data-component~="ui-separator"][aria-orientation="vertical"][data-v-7451a37c] {
7045
7195
  block-size: auto;
7046
7196
  border-block-start: 0;
7047
7197
  border-inline-start: var(--ui-border-width) solid
7048
7198
  var(--ui-separator-color, var(--ui-border-divider));
7049
7199
  }
7200
+ [data-component~="ui-separator"][data-ui-separator-state~="selectable"][data-v-7451a37c] {
7201
+ min-block-size: var(--ui-control-size-sm);
7202
+ border: 0;
7203
+ background: linear-gradient(
7204
+ var(--ui-separator-color, var(--ui-border-divider)),
7205
+ var(--ui-separator-color, var(--ui-border-divider))
7206
+ ) center / 100% var(--ui-border-width) no-repeat;
7207
+ cursor: pointer;
7208
+ }
7209
+ [data-component~="ui-separator"][data-ui-separator-state~="selectable"][data-v-7451a37c]:hover {
7210
+ background-color: var(--ui-surface-hover);
7211
+ }
7212
+ [data-component~="ui-separator"][data-ui-separator-state~="selected"][data-v-7451a37c] {
7213
+ outline: var(--ui-focus-width) solid var(--ui-focus-ring);
7214
+ outline-offset: var(--ui-focus-width);
7215
+ border-radius: var(--ui-radius-sm);
7216
+ }
7050
7217
 
7051
7218
  /* This component's hooks style the element they are set on, and never a nested one. */
7052
7219
  @property --ui-sidebar-backdrop {
@@ -9364,13 +9531,6 @@ html[data-ui-input-modality="touch"]
9364
9531
  pointer-events: none;
9365
9532
  }
9366
9533
 
9367
- .looma-editor .ProseMirror img {
9368
- max-width: 100%;
9369
- height: auto;
9370
- margin: var(--ui-space-3) 0;
9371
- border-radius: var(--ui-radius-md);
9372
- }
9373
-
9374
9534
  .looma-editor .ProseMirror img[data-looma-image]:focus-visible {
9375
9535
  outline: var(--ui-focus-width) solid var(--ui-focus-ring);
9376
9536
  outline-offset: calc(var(--ui-focus-width) + var(--ui-border-width));