@threadlabs/looma 0.23.21 → 0.23.23
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/components/shared/overlay.js +1 -1
- package/components/ui-button/ui-button.html +68 -2
- package/components/ui-image/ui-image.html +177 -0
- package/components/ui-image/ui-image.js +107 -0
- package/components/ui-menu/ui-menu.js +1 -1
- package/components/ui-popover/ui-popover.js +4 -1
- package/components/ui-separator/ui-separator.html +26 -2
- package/dist/index.js +24 -23
- package/editor/chunks/extensions.js +633 -20
- package/editor/extensions/block-selection.d.ts +6 -0
- package/editor/extensions/expand.d.ts +31 -0
- package/editor/extensions/image.d.ts +12 -0
- package/editor/extensions/index.d.ts +4 -1
- package/editor/extensions/index.js +2 -2
- package/editor/extensions/preset.d.ts +8 -0
- package/editor/extensions/slash-command.d.ts +31 -3
- package/editor/extensions/table-of-contents.d.ts +58 -0
- package/editor/index.js +2 -2
- package/package.json +1 -1
- package/styles/ui-button.css +39 -0
- package/styles/ui-image.css +153 -0
- package/styles/ui-separator.css +22 -2
- package/vanilla/UiButton.d.ts +1 -1
- package/vanilla/UiButton.js +126 -10
- package/vanilla/UiImage.d.ts +21 -0
- package/vanilla/UiImage.js +84 -0
- package/vanilla/UiSeparator.d.ts +3 -0
- package/vanilla/UiSeparator.js +14 -4
- package/vanilla/index.js +1 -0
- package/vue/UiButton.d.ts +18 -6
- package/vue/UiButton.vue +269 -8
- package/vue/UiImage.d.ts +100 -0
- package/vue/UiImage.js +2 -0
- package/vue/UiImage.vue +463 -0
- package/vue/UiListItem.d.ts +1 -1
- package/vue/UiSection.d.ts +1 -1
- package/vue/UiSeparator.d.ts +27 -0
- package/vue/UiSeparator.vue +94 -3
- package/vue/UiSidebar.d.ts +1 -1
- package/vue/chunks/UiButton.js +196 -12
- package/vue/chunks/UiImage.js +313 -0
- package/vue/chunks/UiSeparator.js +106 -22
- package/vue/components.css +252 -53
- package/vue/editor/LoomaEditor.d.ts +19 -2
- package/vue/editor/divider.d.ts +6 -0
- package/vue/editor/expand.d.ts +7 -0
- package/vue/editor/image-controls.d.ts +19 -0
- package/vue/editor/image-delivery.d.ts +2 -2
- package/vue/editor/image.d.ts +7 -0
- package/vue/editor/index.d.ts +1 -1
- package/vue/editor/index.js +1188 -52
- package/vue/editor/table-of-contents.d.ts +7 -0
- package/vue/index.d.ts +1 -0
- package/vue/index.js +2 -1
package/vue/UiImage.vue
ADDED
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
<!-- Generated by HTML Next 1.0.0-alpha.26 for Vue 3.5. Do not edit. -->
|
|
2
|
+
<script setup lang="ts">
|
|
3
|
+
import { computed, getCurrentInstance, ref, useTemplateRef, watchSyncEffect } from 'vue'
|
|
4
|
+
import type { PropType } from 'vue'
|
|
5
|
+
import { createDispatch, useComponentHost } from './host'
|
|
6
|
+
import { checkedProp, propValidityState, vPropValidity } from './props'
|
|
7
|
+
|
|
8
|
+
defineOptions({ inheritAttrs: false })
|
|
9
|
+
|
|
10
|
+
const propValidityContract = {
|
|
11
|
+
props: {
|
|
12
|
+
alt: {
|
|
13
|
+
type: { kind: 'terminal', name: 'string' },
|
|
14
|
+
required: false,
|
|
15
|
+
target: { attribute: 'alt' },
|
|
16
|
+
description: 'A text alternative for the image.',
|
|
17
|
+
default: '',
|
|
18
|
+
},
|
|
19
|
+
height: {
|
|
20
|
+
type: { kind: 'terminal', name: 'integer' },
|
|
21
|
+
required: false,
|
|
22
|
+
target: { attribute: 'height' },
|
|
23
|
+
description: 'Image height in CSS pixels; resizing preserves the intrinsic aspect ratio.',
|
|
24
|
+
},
|
|
25
|
+
placement: {
|
|
26
|
+
type: { kind: 'terminal', name: 'keyword' },
|
|
27
|
+
required: false,
|
|
28
|
+
target: { attribute: 'placement' },
|
|
29
|
+
description:
|
|
30
|
+
'Block keeps text below; center centers the image; wrap-left and wrap-right let following text flow beside it.',
|
|
31
|
+
values: ['block', 'center', 'wrap-left', 'wrap-right'],
|
|
32
|
+
default: 'block',
|
|
33
|
+
},
|
|
34
|
+
resizable: {
|
|
35
|
+
type: { kind: 'terminal', name: 'boolean' },
|
|
36
|
+
required: false,
|
|
37
|
+
target: { attribute: 'resizable' },
|
|
38
|
+
description:
|
|
39
|
+
'Shows four corner handles while selected. Drag to resize, or focus a handle and use arrow keys; Shift uses a larger increment.',
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
selected: {
|
|
43
|
+
type: { kind: 'terminal', name: 'boolean' },
|
|
44
|
+
required: false,
|
|
45
|
+
target: { attribute: 'selected' },
|
|
46
|
+
description: 'Outlines the media as the current selection.',
|
|
47
|
+
default: false,
|
|
48
|
+
},
|
|
49
|
+
src: {
|
|
50
|
+
type: { kind: 'terminal', name: 'string' },
|
|
51
|
+
required: false,
|
|
52
|
+
target: { attribute: 'src' },
|
|
53
|
+
description: 'The image source, used by the default media.',
|
|
54
|
+
default: '',
|
|
55
|
+
},
|
|
56
|
+
width: {
|
|
57
|
+
type: { kind: 'terminal', name: 'integer' },
|
|
58
|
+
required: false,
|
|
59
|
+
target: { attribute: 'width' },
|
|
60
|
+
description:
|
|
61
|
+
'Image width in CSS pixels; omitted uses intrinsic size in block/center placement or responsive sizing when wrapping.',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
} as const
|
|
65
|
+
const props = defineProps({
|
|
66
|
+
alt: { type: null as unknown as PropType<string | null>, default: '' },
|
|
67
|
+
height: { type: null as unknown as PropType<number | null>, default: null },
|
|
68
|
+
placement: {
|
|
69
|
+
type: null as unknown as PropType<'block' | 'center' | 'wrap-left' | 'wrap-right' | null>,
|
|
70
|
+
default: 'block',
|
|
71
|
+
},
|
|
72
|
+
resizable: { type: null as unknown as PropType<boolean | null>, default: false },
|
|
73
|
+
selected: { type: null as unknown as PropType<boolean | null>, default: false },
|
|
74
|
+
src: { type: null as unknown as PropType<string | null>, default: '' },
|
|
75
|
+
width: { type: null as unknown as PropType<number | null>, default: null },
|
|
76
|
+
})
|
|
77
|
+
const acceptedProps: Record<string, unknown> = {
|
|
78
|
+
alt: '',
|
|
79
|
+
height: null,
|
|
80
|
+
placement: 'block',
|
|
81
|
+
resizable: false,
|
|
82
|
+
selected: false,
|
|
83
|
+
src: '',
|
|
84
|
+
width: null,
|
|
85
|
+
}
|
|
86
|
+
const checkedProps = computed(() => ({
|
|
87
|
+
alt: checkedProp<string>(
|
|
88
|
+
props['alt'],
|
|
89
|
+
{ kind: 'terminal', name: 'string' },
|
|
90
|
+
false,
|
|
91
|
+
'alt',
|
|
92
|
+
acceptedProps,
|
|
93
|
+
) as string,
|
|
94
|
+
height: checkedProp<number>(
|
|
95
|
+
props['height'],
|
|
96
|
+
{ kind: 'terminal', name: 'integer' },
|
|
97
|
+
false,
|
|
98
|
+
'height',
|
|
99
|
+
acceptedProps,
|
|
100
|
+
),
|
|
101
|
+
placement: checkedProp<'block' | 'center' | 'wrap-left' | 'wrap-right'>(
|
|
102
|
+
props['placement'],
|
|
103
|
+
{ kind: 'terminal', name: 'keyword' },
|
|
104
|
+
false,
|
|
105
|
+
'placement',
|
|
106
|
+
acceptedProps,
|
|
107
|
+
) as 'block' | 'center' | 'wrap-left' | 'wrap-right',
|
|
108
|
+
resizable: checkedProp<boolean>(
|
|
109
|
+
props['resizable'],
|
|
110
|
+
{ kind: 'terminal', name: 'boolean' },
|
|
111
|
+
false,
|
|
112
|
+
'resizable',
|
|
113
|
+
acceptedProps,
|
|
114
|
+
) as boolean,
|
|
115
|
+
selected: checkedProp<boolean>(
|
|
116
|
+
props['selected'],
|
|
117
|
+
{ kind: 'terminal', name: 'boolean' },
|
|
118
|
+
false,
|
|
119
|
+
'selected',
|
|
120
|
+
acceptedProps,
|
|
121
|
+
) as boolean,
|
|
122
|
+
src: checkedProp<string>(
|
|
123
|
+
props['src'],
|
|
124
|
+
{ kind: 'terminal', name: 'string' },
|
|
125
|
+
false,
|
|
126
|
+
'src',
|
|
127
|
+
acceptedProps,
|
|
128
|
+
) as string,
|
|
129
|
+
width: checkedProp<number>(
|
|
130
|
+
props['width'],
|
|
131
|
+
{ kind: 'terminal', name: 'integer' },
|
|
132
|
+
false,
|
|
133
|
+
'width',
|
|
134
|
+
acceptedProps,
|
|
135
|
+
),
|
|
136
|
+
}))
|
|
137
|
+
void checkedProps.value
|
|
138
|
+
watchSyncEffect(() => {
|
|
139
|
+
void checkedProps.value
|
|
140
|
+
})
|
|
141
|
+
function nativeAttrs(attrs: Record<string, unknown>): Record<string, unknown> {
|
|
142
|
+
const names = Object.keys(attrs)
|
|
143
|
+
if (!names.some((name) => Object.hasOwn(Object.prototype, name))) return attrs
|
|
144
|
+
return Object.fromEntries(names.map((name) => [
|
|
145
|
+
Object.hasOwn(Object.prototype, name)
|
|
146
|
+
? name === '__proto__' ? '__Proto__' : name[0]!.toUpperCase() + name.slice(1)
|
|
147
|
+
: name,
|
|
148
|
+
attrs[name],
|
|
149
|
+
]))
|
|
150
|
+
}
|
|
151
|
+
const componentInstance = getCurrentInstance()
|
|
152
|
+
function reflectedProp(
|
|
153
|
+
name: string,
|
|
154
|
+
kebab: string,
|
|
155
|
+
value: unknown,
|
|
156
|
+
fallback: string | undefined,
|
|
157
|
+
bound: boolean,
|
|
158
|
+
separator?: string,
|
|
159
|
+
): string | undefined {
|
|
160
|
+
const incoming = componentInstance?.vnode.props
|
|
161
|
+
if (
|
|
162
|
+
!bound
|
|
163
|
+
&& (incoming === null || incoming === undefined
|
|
164
|
+
|| (!Object.hasOwn(incoming, name) && !Object.hasOwn(incoming, kebab)))
|
|
165
|
+
) return fallback
|
|
166
|
+
if (value === null || value === undefined) return undefined
|
|
167
|
+
return Array.isArray(value) && separator !== undefined
|
|
168
|
+
? value.join(separator)
|
|
169
|
+
: typeof value === 'object'
|
|
170
|
+
? JSON.stringify(value)
|
|
171
|
+
: String(value)
|
|
172
|
+
}
|
|
173
|
+
const hydrationInstance = getCurrentInstance()
|
|
174
|
+
const emit = defineEmits<{
|
|
175
|
+
'update:height': [value: number]
|
|
176
|
+
'update:width': [value: number]
|
|
177
|
+
resize: [
|
|
178
|
+
event: CustomEvent<
|
|
179
|
+
{
|
|
180
|
+
readonly width: number
|
|
181
|
+
readonly height: number
|
|
182
|
+
readonly phase: 'preview' | 'commit' | 'cancel'
|
|
183
|
+
readonly trigger: 'pointer' | 'keyboard'
|
|
184
|
+
}
|
|
185
|
+
>,
|
|
186
|
+
]
|
|
187
|
+
}>()
|
|
188
|
+
|
|
189
|
+
const root = ref<HTMLElement | null>(null)
|
|
190
|
+
const frameElement = useTemplateRef<HTMLElement>('frame')
|
|
191
|
+
const hydrationNode = hydrationInstance?.vnode.el
|
|
192
|
+
if (
|
|
193
|
+
typeof window !== 'undefined' && hydrationNode != null
|
|
194
|
+
&& (!(hydrationNode instanceof Element) || hydrationNode.localName !== ('figure'))
|
|
195
|
+
) {
|
|
196
|
+
throw Object.assign(new Error('HR005: Server markup for <ui-image> has an incompatible root.'), {
|
|
197
|
+
name: 'HtmlDiagnosticError',
|
|
198
|
+
diagnostic: Object.freeze({
|
|
199
|
+
code: 'HR005',
|
|
200
|
+
message: 'Server markup for <ui-image> has an incompatible root.',
|
|
201
|
+
}),
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** The values the styles' :host-state() rules test. */
|
|
206
|
+
const hostState = computed(() =>
|
|
207
|
+
[
|
|
208
|
+
checkedProps.value.placement && 'placement',
|
|
209
|
+
checkedProps.value.placement != null
|
|
210
|
+
&& `placement=${encodeURIComponent(checkedProps.value.placement)}`,
|
|
211
|
+
checkedProps.value.selected && 'selected',
|
|
212
|
+
].filter(Boolean).join(' ')
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
const isResizeDetail = (detail: unknown): boolean =>
|
|
216
|
+
detail !== null && typeof detail === 'object' && !Array.isArray(detail)
|
|
217
|
+
&& Number.isInteger((detail as Record<string, unknown>)['width'])
|
|
218
|
+
&& Number.isInteger((detail as Record<string, unknown>)['height'])
|
|
219
|
+
&& ((detail as Record<string, unknown>)['phase'] === 'preview'
|
|
220
|
+
|| (detail as Record<string, unknown>)['phase'] === 'commit'
|
|
221
|
+
|| (detail as Record<string, unknown>)['phase'] === 'cancel')
|
|
222
|
+
&& ((detail as Record<string, unknown>)['trigger'] === 'pointer'
|
|
223
|
+
|| (detail as Record<string, unknown>)['trigger'] === 'keyboard')
|
|
224
|
+
&& Object.keys(detail as object).every((key) =>
|
|
225
|
+
['width', 'height', 'phase', 'trigger'].includes(key)
|
|
226
|
+
)
|
|
227
|
+
const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
|
|
228
|
+
checks: {
|
|
229
|
+
resize: isResizeDetail,
|
|
230
|
+
},
|
|
231
|
+
modeled: ['height', 'width'],
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
useComponentHost(() => import('../components/ui-image/ui-image.js'), {
|
|
235
|
+
root,
|
|
236
|
+
dispatch,
|
|
237
|
+
controllerSource: {
|
|
238
|
+
specifier: '../components/ui-image/ui-image.js',
|
|
239
|
+
definition: './components/ui-image/ui-image.html',
|
|
240
|
+
},
|
|
241
|
+
props: checkedProps,
|
|
242
|
+
propInputs: (name: string) => {
|
|
243
|
+
const incoming = hydrationInstance?.vnode.props
|
|
244
|
+
const kebab = name.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase())
|
|
245
|
+
return incoming !== null && incoming !== undefined
|
|
246
|
+
? (incoming[name] ?? incoming[kebab] ?? null)
|
|
247
|
+
: null
|
|
248
|
+
},
|
|
249
|
+
propNames: ['alt', 'height', 'placement', 'resizable', 'selected', 'src', 'width'],
|
|
250
|
+
propValidity: (name: string) =>
|
|
251
|
+
propValidityState({ contract: propValidityContract, values: { ...props } }, name),
|
|
252
|
+
refs: { frame: frameElement },
|
|
253
|
+
})
|
|
254
|
+
</script>
|
|
255
|
+
|
|
256
|
+
<template>
|
|
257
|
+
<figure
|
|
258
|
+
data-component="ui-image"
|
|
259
|
+
v-bind="nativeAttrs($attrs)"
|
|
260
|
+
v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
|
|
261
|
+
:data-alt="reflectedProp('alt', 'alt', checkedProps.alt, undefined, false)"
|
|
262
|
+
:data-height="reflectedProp('height', 'height', checkedProps.height, undefined, false)"
|
|
263
|
+
:data-placement="reflectedProp('placement', 'placement', checkedProps.placement, undefined, false)"
|
|
264
|
+
:data-resizable="reflectedProp('resizable', 'resizable', checkedProps.resizable, undefined, false)"
|
|
265
|
+
:data-selected="reflectedProp('selected', 'selected', checkedProps.selected, undefined, false)"
|
|
266
|
+
:data-src="reflectedProp('src', 'src', checkedProps.src, undefined, false)"
|
|
267
|
+
:data-width="reflectedProp('width', 'width', checkedProps.width, undefined, false)"
|
|
268
|
+
:data-ui-image-state="hostState || undefined"
|
|
269
|
+
ref="root"
|
|
270
|
+
>
|
|
271
|
+
<div class="frame" ref="frame">
|
|
272
|
+
<slot name="media"><img
|
|
273
|
+
:src="checkedProps.src ?? undefined"
|
|
274
|
+
:alt="checkedProps.alt ?? undefined"
|
|
275
|
+
:width="checkedProps.width ?? undefined"
|
|
276
|
+
:height="checkedProps.height ?? undefined"
|
|
277
|
+
></slot>
|
|
278
|
+
<div class="handles" :hidden="!(checkedProps.selected && checkedProps.resizable)">
|
|
279
|
+
<button
|
|
280
|
+
type="button"
|
|
281
|
+
class="handle"
|
|
282
|
+
data-corner="top-left"
|
|
283
|
+
aria-label="Resize image from top left"
|
|
284
|
+
>
|
|
285
|
+
</button>
|
|
286
|
+
<button
|
|
287
|
+
type="button"
|
|
288
|
+
class="handle"
|
|
289
|
+
data-corner="top-right"
|
|
290
|
+
aria-label="Resize image from top right"
|
|
291
|
+
>
|
|
292
|
+
</button>
|
|
293
|
+
<button
|
|
294
|
+
type="button"
|
|
295
|
+
class="handle"
|
|
296
|
+
data-corner="bottom-left"
|
|
297
|
+
aria-label="Resize image from bottom left"
|
|
298
|
+
>
|
|
299
|
+
</button>
|
|
300
|
+
<button
|
|
301
|
+
type="button"
|
|
302
|
+
class="handle"
|
|
303
|
+
data-corner="bottom-right"
|
|
304
|
+
aria-label="Resize image from bottom right"
|
|
305
|
+
>
|
|
306
|
+
</button>
|
|
307
|
+
</div>
|
|
308
|
+
<slot name="controls" />
|
|
309
|
+
</div>
|
|
310
|
+
</figure>
|
|
311
|
+
</template>
|
|
312
|
+
|
|
313
|
+
<style scoped>
|
|
314
|
+
[data-component~="ui-image"] {
|
|
315
|
+
display: flex;
|
|
316
|
+
justify-content: flex-start;
|
|
317
|
+
box-sizing: border-box;
|
|
318
|
+
max-inline-size: 100%;
|
|
319
|
+
min-inline-size: 0;
|
|
320
|
+
margin: 0;
|
|
321
|
+
padding: var(--ui-space-3) 0;
|
|
322
|
+
}
|
|
323
|
+
[data-component~="ui-image"][data-ui-image-state~="placement=center"] {
|
|
324
|
+
justify-content: center;
|
|
325
|
+
}
|
|
326
|
+
[data-component~="ui-image"][data-ui-image-state~="placement=wrap-left"] {
|
|
327
|
+
float: left;
|
|
328
|
+
padding-inline-end: var(--ui-space-4);
|
|
329
|
+
}
|
|
330
|
+
[data-component~="ui-image"][data-ui-image-state~="placement=wrap-right"] {
|
|
331
|
+
float: right;
|
|
332
|
+
padding-inline-start: var(--ui-space-4);
|
|
333
|
+
}
|
|
334
|
+
[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"]) {
|
|
335
|
+
inline-size: calc(var(--_ui-image-width, calc(100% / 3)) + var(--ui-space-4));
|
|
336
|
+
}
|
|
337
|
+
[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"])
|
|
338
|
+
.frame {
|
|
339
|
+
inline-size: 100%;
|
|
340
|
+
}
|
|
341
|
+
[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"])
|
|
342
|
+
.frame
|
|
343
|
+
img,
|
|
344
|
+
[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"])
|
|
345
|
+
.frame
|
|
346
|
+
:slotted(img) {
|
|
347
|
+
inline-size: 100%;
|
|
348
|
+
}
|
|
349
|
+
.frame {
|
|
350
|
+
position: relative;
|
|
351
|
+
flex: 0 1 auto;
|
|
352
|
+
inline-size: var(--_ui-image-width, fit-content);
|
|
353
|
+
max-inline-size: 100%;
|
|
354
|
+
min-inline-size: 0;
|
|
355
|
+
align-self: flex-start;
|
|
356
|
+
border-radius: var(--ui-radius-md);
|
|
357
|
+
}
|
|
358
|
+
.frame img, .frame :slotted(img) {
|
|
359
|
+
display: block;
|
|
360
|
+
max-inline-size: 100%;
|
|
361
|
+
block-size: auto;
|
|
362
|
+
margin: 0;
|
|
363
|
+
border-radius: inherit;
|
|
364
|
+
}
|
|
365
|
+
[data-component~="ui-image"][data-resizing] .frame img,
|
|
366
|
+
[data-component~="ui-image"][data-resizing] .frame :slotted(img) {
|
|
367
|
+
inline-size: 100%;
|
|
368
|
+
}
|
|
369
|
+
[data-component~="ui-image"][data-ui-image-state~="selected"] .frame {
|
|
370
|
+
outline: var(--ui-focus-width) solid var(--ui-focus-ring);
|
|
371
|
+
outline-offset: var(--ui-border-width);
|
|
372
|
+
}
|
|
373
|
+
.handle {
|
|
374
|
+
position: absolute;
|
|
375
|
+
z-index: 1;
|
|
376
|
+
inline-size: 24px;
|
|
377
|
+
block-size: 24px;
|
|
378
|
+
padding: 0;
|
|
379
|
+
border: 0;
|
|
380
|
+
background: transparent;
|
|
381
|
+
touch-action: none;
|
|
382
|
+
}
|
|
383
|
+
.handle::after {
|
|
384
|
+
content: "";
|
|
385
|
+
position: absolute;
|
|
386
|
+
inset: 8px;
|
|
387
|
+
background: var(--ui-surface);
|
|
388
|
+
border: var(--ui-border-width) solid var(--ui-focus-ring);
|
|
389
|
+
border-radius: var(--ui-radius-sm);
|
|
390
|
+
}
|
|
391
|
+
.handle:focus-visible {
|
|
392
|
+
outline: var(--ui-focus-width) solid var(--ui-focus-ring);
|
|
393
|
+
border-radius: var(--ui-radius-sm);
|
|
394
|
+
}
|
|
395
|
+
.handle[data-corner="top-left"] {
|
|
396
|
+
top: -12px;
|
|
397
|
+
left: -12px;
|
|
398
|
+
cursor: nwse-resize;
|
|
399
|
+
}
|
|
400
|
+
.handle[data-corner="top-right"] {
|
|
401
|
+
top: -12px;
|
|
402
|
+
right: -12px;
|
|
403
|
+
cursor: nesw-resize;
|
|
404
|
+
}
|
|
405
|
+
.handle[data-corner="bottom-left"] {
|
|
406
|
+
bottom: -12px;
|
|
407
|
+
left: -12px;
|
|
408
|
+
cursor: nesw-resize;
|
|
409
|
+
}
|
|
410
|
+
.handle[data-corner="bottom-right"] {
|
|
411
|
+
bottom: -12px;
|
|
412
|
+
right: -12px;
|
|
413
|
+
cursor: nwse-resize;
|
|
414
|
+
}
|
|
415
|
+
.handles[hidden], [data-component~="ui-image"][hidden] {
|
|
416
|
+
display: none;
|
|
417
|
+
}
|
|
418
|
+
@media (max-width: 767px) {
|
|
419
|
+
[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"]) {
|
|
420
|
+
float: none;
|
|
421
|
+
inline-size: 100%;
|
|
422
|
+
padding-inline: 0;
|
|
423
|
+
}
|
|
424
|
+
[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"])
|
|
425
|
+
.handles {
|
|
426
|
+
display: none;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
@media (pointer: coarse) {
|
|
430
|
+
.handle {
|
|
431
|
+
inline-size: 44px;
|
|
432
|
+
block-size: 44px;
|
|
433
|
+
}
|
|
434
|
+
.handle::after {
|
|
435
|
+
inset: 18px;
|
|
436
|
+
}
|
|
437
|
+
.handle[data-corner="top-left"] {
|
|
438
|
+
top: -22px;
|
|
439
|
+
left: -22px;
|
|
440
|
+
}
|
|
441
|
+
.handle[data-corner="top-right"] {
|
|
442
|
+
top: -22px;
|
|
443
|
+
right: -22px;
|
|
444
|
+
}
|
|
445
|
+
.handle[data-corner="bottom-left"] {
|
|
446
|
+
bottom: -22px;
|
|
447
|
+
left: -22px;
|
|
448
|
+
}
|
|
449
|
+
.handle[data-corner="bottom-right"] {
|
|
450
|
+
bottom: -22px;
|
|
451
|
+
right: -22px;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
@media (forced-colors: active) {
|
|
455
|
+
[data-component~="ui-image"][data-ui-image-state~="selected"] .frame, .handle:focus-visible {
|
|
456
|
+
outline-color: Highlight;
|
|
457
|
+
}
|
|
458
|
+
.handle::after {
|
|
459
|
+
border-color: Highlight;
|
|
460
|
+
background: Canvas;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
</style>
|
package/vue/UiListItem.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
44
44
|
default: boolean;
|
|
45
45
|
};
|
|
46
46
|
}>> & Readonly<{}>, {
|
|
47
|
-
variant: "
|
|
47
|
+
variant: "card" | "row" | null;
|
|
48
48
|
current: boolean | null;
|
|
49
49
|
wrap: boolean | null;
|
|
50
50
|
highlighted: boolean | null;
|
package/vue/UiSection.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
35
35
|
};
|
|
36
36
|
}>> & Readonly<{}>, {
|
|
37
37
|
tone: "neutral" | "danger" | null;
|
|
38
|
-
variant: "
|
|
38
|
+
variant: "card" | "plain" | "divided" | null;
|
|
39
39
|
heading: string | null;
|
|
40
40
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
41
41
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
package/vue/UiSeparator.d.ts
CHANGED
|
@@ -1,16 +1,43 @@
|
|
|
1
1
|
import type { PropType } from 'vue';
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
3
|
+
emphasis: {
|
|
4
|
+
type: PropType<"normal" | "strong" | null>;
|
|
5
|
+
default: string;
|
|
6
|
+
};
|
|
3
7
|
orientation: {
|
|
4
8
|
type: PropType<"horizontal" | "vertical" | null>;
|
|
5
9
|
default: string;
|
|
6
10
|
};
|
|
11
|
+
selectable: {
|
|
12
|
+
type: PropType<boolean | null>;
|
|
13
|
+
default: boolean;
|
|
14
|
+
};
|
|
15
|
+
selected: {
|
|
16
|
+
type: PropType<boolean | null>;
|
|
17
|
+
default: boolean;
|
|
18
|
+
};
|
|
7
19
|
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
20
|
+
emphasis: {
|
|
21
|
+
type: PropType<"normal" | "strong" | null>;
|
|
22
|
+
default: string;
|
|
23
|
+
};
|
|
8
24
|
orientation: {
|
|
9
25
|
type: PropType<"horizontal" | "vertical" | null>;
|
|
10
26
|
default: string;
|
|
11
27
|
};
|
|
28
|
+
selectable: {
|
|
29
|
+
type: PropType<boolean | null>;
|
|
30
|
+
default: boolean;
|
|
31
|
+
};
|
|
32
|
+
selected: {
|
|
33
|
+
type: PropType<boolean | null>;
|
|
34
|
+
default: boolean;
|
|
35
|
+
};
|
|
12
36
|
}>> & Readonly<{}>, {
|
|
37
|
+
selected: boolean | null;
|
|
13
38
|
orientation: "vertical" | "horizontal" | null;
|
|
39
|
+
emphasis: "strong" | "normal" | null;
|
|
40
|
+
selectable: boolean | null;
|
|
14
41
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
15
42
|
declare const _default: typeof __VLS_export;
|
|
16
43
|
export default _default;
|
package/vue/UiSeparator.vue
CHANGED
|
@@ -8,6 +8,15 @@ defineOptions({ inheritAttrs: false })
|
|
|
8
8
|
|
|
9
9
|
const propValidityContract = {
|
|
10
10
|
props: {
|
|
11
|
+
emphasis: {
|
|
12
|
+
type: { kind: 'terminal', name: 'keyword' },
|
|
13
|
+
required: false,
|
|
14
|
+
target: { attribute: 'emphasis' },
|
|
15
|
+
description:
|
|
16
|
+
'Normal uses the decorative divider color; strong uses the stronger enclosing-edge color for clearer separation.',
|
|
17
|
+
values: ['normal', 'strong'],
|
|
18
|
+
default: 'normal',
|
|
19
|
+
},
|
|
11
20
|
orientation: {
|
|
12
21
|
type: { kind: 'terminal', name: 'keyword' },
|
|
13
22
|
required: false,
|
|
@@ -17,16 +26,47 @@ const propValidityContract = {
|
|
|
17
26
|
values: ['horizontal', 'vertical'],
|
|
18
27
|
default: 'horizontal',
|
|
19
28
|
},
|
|
29
|
+
selectable: {
|
|
30
|
+
type: { kind: 'terminal', name: 'boolean' },
|
|
31
|
+
required: false,
|
|
32
|
+
target: { attribute: 'selectable' },
|
|
33
|
+
description:
|
|
34
|
+
'Gives a document divider a pointer-sized hit area. The editor owns selection and deletion.',
|
|
35
|
+
default: false,
|
|
36
|
+
},
|
|
37
|
+
selected: {
|
|
38
|
+
type: { kind: 'terminal', name: 'boolean' },
|
|
39
|
+
required: false,
|
|
40
|
+
target: { attribute: 'selected' },
|
|
41
|
+
description:
|
|
42
|
+
'Shows the selected document divider. Selection does not change separator semantics.',
|
|
43
|
+
default: false,
|
|
44
|
+
},
|
|
20
45
|
},
|
|
21
46
|
} as const
|
|
22
47
|
const props = defineProps({
|
|
48
|
+
emphasis: { type: null as unknown as PropType<'normal' | 'strong' | null>, default: 'normal' },
|
|
23
49
|
orientation: {
|
|
24
50
|
type: null as unknown as PropType<'horizontal' | 'vertical' | null>,
|
|
25
51
|
default: 'horizontal',
|
|
26
52
|
},
|
|
53
|
+
selectable: { type: null as unknown as PropType<boolean | null>, default: false },
|
|
54
|
+
selected: { type: null as unknown as PropType<boolean | null>, default: false },
|
|
27
55
|
})
|
|
28
|
-
const acceptedProps: Record<string, unknown> = {
|
|
56
|
+
const acceptedProps: Record<string, unknown> = {
|
|
57
|
+
emphasis: 'normal',
|
|
58
|
+
orientation: 'horizontal',
|
|
59
|
+
selectable: false,
|
|
60
|
+
selected: false,
|
|
61
|
+
}
|
|
29
62
|
const checkedProps = computed(() => ({
|
|
63
|
+
emphasis: checkedProp<'normal' | 'strong'>(
|
|
64
|
+
props['emphasis'],
|
|
65
|
+
{ kind: 'terminal', name: 'keyword' },
|
|
66
|
+
false,
|
|
67
|
+
'emphasis',
|
|
68
|
+
acceptedProps,
|
|
69
|
+
) as 'normal' | 'strong',
|
|
30
70
|
orientation: checkedProp<'horizontal' | 'vertical'>(
|
|
31
71
|
props['orientation'],
|
|
32
72
|
{ kind: 'terminal', name: 'keyword' },
|
|
@@ -34,6 +74,20 @@ const checkedProps = computed(() => ({
|
|
|
34
74
|
'orientation',
|
|
35
75
|
acceptedProps,
|
|
36
76
|
) as 'horizontal' | 'vertical',
|
|
77
|
+
selectable: checkedProp<boolean>(
|
|
78
|
+
props['selectable'],
|
|
79
|
+
{ kind: 'terminal', name: 'boolean' },
|
|
80
|
+
false,
|
|
81
|
+
'selectable',
|
|
82
|
+
acceptedProps,
|
|
83
|
+
) as boolean,
|
|
84
|
+
selected: checkedProp<boolean>(
|
|
85
|
+
props['selected'],
|
|
86
|
+
{ kind: 'terminal', name: 'boolean' },
|
|
87
|
+
false,
|
|
88
|
+
'selected',
|
|
89
|
+
acceptedProps,
|
|
90
|
+
) as boolean,
|
|
37
91
|
}))
|
|
38
92
|
void checkedProps.value
|
|
39
93
|
watchSyncEffect(() => {
|
|
@@ -89,6 +143,17 @@ if (
|
|
|
89
143
|
},
|
|
90
144
|
)
|
|
91
145
|
}
|
|
146
|
+
|
|
147
|
+
/** The values the styles' :host-state() rules test. */
|
|
148
|
+
const hostState = computed(() =>
|
|
149
|
+
[
|
|
150
|
+
checkedProps.value.emphasis && 'emphasis',
|
|
151
|
+
checkedProps.value.emphasis != null
|
|
152
|
+
&& `emphasis=${encodeURIComponent(checkedProps.value.emphasis)}`,
|
|
153
|
+
checkedProps.value.selectable && 'selectable',
|
|
154
|
+
checkedProps.value.selected && 'selected',
|
|
155
|
+
].filter(Boolean).join(' ')
|
|
156
|
+
)
|
|
92
157
|
</script>
|
|
93
158
|
|
|
94
159
|
<template>
|
|
@@ -97,7 +162,11 @@ if (
|
|
|
97
162
|
v-bind="nativeAttrs($attrs)"
|
|
98
163
|
:aria-orientation="checkedProps.orientation ?? undefined"
|
|
99
164
|
v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
|
|
165
|
+
:data-emphasis="reflectedProp('emphasis', 'emphasis', checkedProps.emphasis, undefined, false)"
|
|
100
166
|
:data-orientation="reflectedProp('orientation', 'orientation', checkedProps.orientation, undefined, false)"
|
|
167
|
+
:data-selectable="reflectedProp('selectable', 'selectable', checkedProps.selectable, undefined, false)"
|
|
168
|
+
:data-selected="reflectedProp('selected', 'selected', checkedProps.selected, undefined, false)"
|
|
169
|
+
:data-ui-separator-state="hostState || undefined"
|
|
101
170
|
>
|
|
102
171
|
</template>
|
|
103
172
|
|
|
@@ -115,13 +184,35 @@ if (
|
|
|
115
184
|
margin: 0;
|
|
116
185
|
border: 0;
|
|
117
186
|
border-block-start: var(--ui-border-width) solid
|
|
118
|
-
var(--ui-separator-color, var(--ui-border-divider));
|
|
187
|
+
var(--ui-separator-color, var(--_separator-color, var(--ui-border-divider)));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
[data-component~="ui-separator"][data-ui-separator-state~="emphasis=strong"] {
|
|
191
|
+
--_separator-color: var(--ui-border-strong);
|
|
119
192
|
}
|
|
120
193
|
|
|
121
194
|
[data-component~="ui-separator"][aria-orientation="vertical"] {
|
|
122
195
|
block-size: auto;
|
|
123
196
|
border-block-start: 0;
|
|
124
197
|
border-inline-start: var(--ui-border-width) solid
|
|
125
|
-
var(--ui-separator-color, var(--ui-border-divider));
|
|
198
|
+
var(--ui-separator-color, var(--_separator-color, var(--ui-border-divider)));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
[data-component~="ui-separator"][data-ui-separator-state~="selectable"] {
|
|
202
|
+
min-block-size: var(--ui-control-size-sm);
|
|
203
|
+
border: 0;
|
|
204
|
+
background: linear-gradient(
|
|
205
|
+
var(--ui-separator-color, var(--ui-border-divider)),
|
|
206
|
+
var(--ui-separator-color, var(--ui-border-divider))
|
|
207
|
+
) center / 100% var(--ui-border-width) no-repeat;
|
|
208
|
+
cursor: pointer;
|
|
209
|
+
}
|
|
210
|
+
[data-component~="ui-separator"][data-ui-separator-state~="selectable"]:hover {
|
|
211
|
+
background-color: var(--ui-surface-hover);
|
|
212
|
+
}
|
|
213
|
+
[data-component~="ui-separator"][data-ui-separator-state~="selected"] {
|
|
214
|
+
outline: var(--ui-focus-width) solid var(--ui-focus-ring);
|
|
215
|
+
outline-offset: var(--ui-focus-width);
|
|
216
|
+
border-radius: var(--ui-radius-sm);
|
|
126
217
|
}
|
|
127
218
|
</style>
|
package/vue/UiSidebar.d.ts
CHANGED
|
@@ -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;
|