@threadlabs/looma 0.33.0 → 0.34.0

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 (207) hide show
  1. package/README.md +15 -0
  2. package/bin/looma-docs.mjs +3 -0
  3. package/components/shared/overlay.js +8 -2
  4. package/components/shared/surface-material.js +21 -0
  5. package/components/ui-button/ui-button.html +63 -47
  6. package/components/ui-card/ui-card.html +44 -2
  7. package/components/ui-curve-editor/curve.js +10 -0
  8. package/components/ui-curve-editor/ui-curve-editor.html +181 -0
  9. package/components/ui-curve-editor/ui-curve-editor.js +51 -0
  10. package/components/ui-dialog/ui-dialog.html +62 -1
  11. package/components/ui-dialog/ui-dialog.js +9 -1
  12. package/components/ui-icon-button/ui-icon-button.html +75 -23
  13. package/components/ui-menu/ui-menu.html +60 -0
  14. package/components/ui-menu/ui-menu.js +1 -1
  15. package/components/ui-number-input/arithmetic.js +47 -0
  16. package/components/ui-number-input/ui-number-input.html +62 -0
  17. package/components/ui-number-input/ui-number-input.js +44 -0
  18. package/components/ui-popover/ui-popover.html +64 -1
  19. package/components/ui-popover/ui-popover.js +1 -1
  20. package/components/ui-slider/ui-slider.html +84 -0
  21. package/components/ui-slider/ui-slider.js +29 -0
  22. package/components/ui-tabs/ui-tabs.html +6 -1
  23. package/components/ui-text/ui-text.html +31 -6
  24. package/components/ui-tooltip/ui-tooltip.html +60 -0
  25. package/components/ui-tooltip/ui-tooltip.js +1 -1
  26. package/dist/index.js +46 -43
  27. package/docs/README.md +146 -0
  28. package/docs/card.html +77 -0
  29. package/docs/card.js +47 -0
  30. package/docs/catalog-view.js +18 -0
  31. package/docs/catalog-view.mjs +11 -0
  32. package/docs/catalog.json +23984 -0
  33. package/docs/catalog.mjs +131 -0
  34. package/docs/cli.mjs +26 -0
  35. package/docs/commands.mjs +94 -0
  36. package/docs/customizer-render.mjs +66 -0
  37. package/docs/customizer.js +181 -0
  38. package/docs/documentation.css +16 -0
  39. package/docs/examples/ui-action-bar/examples/01-form-footer.behavior.js +7 -0
  40. package/docs/examples/ui-button/examples/08-loading.behavior.js +21 -0
  41. package/docs/examples/ui-checkbox/examples/02-checked-indeterminate-and-disabled.behavior.js +30 -0
  42. package/docs/examples/ui-combobox/examples/06-selected-values.behavior.js +11 -0
  43. package/docs/examples/ui-search-shell/examples/02-label-dismissible-status-and-footer.behavior.js +34 -0
  44. package/docs/examples/ui-toast/examples/01-authored.behavior.js +15 -0
  45. package/docs/examples/ui-toast/examples/02-danger.behavior.js +2 -0
  46. package/docs/examples/ui-tree/examples/03-max-depth-2-and-hover-expand-delay-300.behavior.js +30 -0
  47. package/docs/examples/ui-tree/examples/06-move-without-dragging.behavior.js +2 -0
  48. package/docs/examples/ui-tree/examples/07-multiple-selection.behavior.js +16 -0
  49. package/docs/examples/ui-tree-item/examples/02-container.behavior.js +1 -0
  50. package/docs/index.d.ts +56 -0
  51. package/docs/index.mjs +4 -0
  52. package/docs/local-server.mjs +68 -0
  53. package/docs/preview.js +22 -0
  54. package/docs/reference.html +1 -0
  55. package/docs/reference.js +36 -0
  56. package/docs/render.mjs +93 -0
  57. package/docs/site.mjs +239 -0
  58. package/docs/store.mjs +92 -0
  59. package/docs/theme-session.mjs +51 -0
  60. package/docs/theme.mjs +219 -0
  61. package/docs/value-editors.mjs +33 -0
  62. package/docs/workspace.mjs +32 -0
  63. package/package.json +28 -4
  64. package/styles/ui-button.css +45 -45
  65. package/styles/ui-card.css +47 -0
  66. package/styles/ui-curve-editor.css +109 -0
  67. package/styles/ui-dialog.css +132 -0
  68. package/styles/ui-icon-button.css +63 -20
  69. package/styles/ui-menu.css +72 -0
  70. package/styles/ui-number-input.css +34 -0
  71. package/styles/ui-popover.css +74 -0
  72. package/styles/ui-slider.css +53 -0
  73. package/styles/ui-tabs.css +6 -1
  74. package/styles/ui-text.css +23 -1
  75. package/styles/ui-tooltip.css +72 -0
  76. package/theme-system.css +26 -10
  77. package/tokens.css +8 -2
  78. package/vanilla/UiButton.d.ts +1 -0
  79. package/vanilla/UiButton.js +195 -130
  80. package/vanilla/UiCard.d.ts +1 -1
  81. package/vanilla/UiCard.js +1 -1
  82. package/vanilla/UiCurveEditor.d.ts +28 -0
  83. package/vanilla/UiCurveEditor.js +134 -0
  84. package/vanilla/UiIconButton.d.ts +2 -1
  85. package/vanilla/UiIconButton.js +58 -31
  86. package/vanilla/UiNumberInput.d.ts +33 -0
  87. package/vanilla/UiNumberInput.js +79 -0
  88. package/vanilla/UiSlider.d.ts +33 -0
  89. package/vanilla/UiSlider.js +125 -0
  90. package/vanilla/UiText.d.ts +2 -2
  91. package/vanilla/UiText.js +45 -11
  92. package/vanilla/index.js +3 -0
  93. package/vue/UiButton.d.ts +6 -0
  94. package/vue/UiButton.vue +155 -56
  95. package/vue/UiCard.d.ts +2 -2
  96. package/vue/UiCard.vue +55 -5
  97. package/vue/UiCurveEditor.d.ts +53 -0
  98. package/vue/UiCurveEditor.js +2 -0
  99. package/vue/UiCurveEditor.vue +427 -0
  100. package/vue/UiDialog.vue +177 -1
  101. package/vue/UiIconButton.d.ts +8 -2
  102. package/vue/UiIconButton.vue +164 -34
  103. package/vue/UiMenu.vue +89 -0
  104. package/vue/UiNumberInput.d.ts +83 -0
  105. package/vue/UiNumberInput.js +2 -0
  106. package/vue/UiNumberInput.vue +370 -0
  107. package/vue/UiPopover.vue +92 -1
  108. package/vue/UiSlider.d.ts +83 -0
  109. package/vue/UiSlider.js +2 -0
  110. package/vue/UiSlider.vue +412 -0
  111. package/vue/UiTabs.vue +6 -1
  112. package/vue/UiText.d.ts +7 -5
  113. package/vue/UiText.vue +104 -22
  114. package/vue/UiTooltip.vue +89 -0
  115. package/vue/chunks/UiActionBar.js +1 -1
  116. package/vue/chunks/UiAffordanceScope.js +2 -2
  117. package/vue/chunks/UiAvatar.js +2 -2
  118. package/vue/chunks/UiAvatarGroup.js +2 -2
  119. package/vue/chunks/UiBadge.js +2 -2
  120. package/vue/chunks/UiBreadcrumbItem.js +2 -2
  121. package/vue/chunks/UiBreadcrumbs.js +2 -2
  122. package/vue/chunks/UiButton.js +94 -11
  123. package/vue/chunks/UiCallout.js +2 -2
  124. package/vue/chunks/UiCard.js +6 -5
  125. package/vue/chunks/UiCheckbox.js +2 -2
  126. package/vue/chunks/UiCluster.js +2 -2
  127. package/vue/chunks/UiColorPicker.js +2 -2
  128. package/vue/chunks/UiCombobox.js +2 -2
  129. package/vue/chunks/UiContainer.js +2 -2
  130. package/vue/chunks/UiContextMenu.js +2 -2
  131. package/vue/chunks/UiCover.js +2 -2
  132. package/vue/chunks/UiCurveEditor.js +413 -0
  133. package/vue/chunks/UiDescriptionItem.js +2 -2
  134. package/vue/chunks/UiDescriptionList.js +2 -2
  135. package/vue/chunks/UiDialog.js +4 -4
  136. package/vue/chunks/UiDisclosure.js +2 -2
  137. package/vue/chunks/UiEditable.js +2 -2
  138. package/vue/chunks/UiEditorBlockActions.js +2 -2
  139. package/vue/chunks/UiEditorChipEditor.js +2 -2
  140. package/vue/chunks/UiEditorCodeLanguage.js +2 -2
  141. package/vue/chunks/UiEditorFootnoteEditor.js +2 -2
  142. package/vue/chunks/UiEditorImageToolbar.js +3 -3
  143. package/vue/chunks/UiEditorInsertTableGrid.js +2 -2
  144. package/vue/chunks/UiEditorLinkCard.js +3 -3
  145. package/vue/chunks/UiEditorLinkForm.js +3 -3
  146. package/vue/chunks/UiEditorMentionMenu.js +2 -2
  147. package/vue/chunks/UiEditorMentionMenuItem.js +2 -2
  148. package/vue/chunks/UiEditorSlashMenu.js +2 -2
  149. package/vue/chunks/UiEditorSlashMenuGroup.js +2 -2
  150. package/vue/chunks/UiEditorSlashMenuItem.js +2 -2
  151. package/vue/chunks/UiEditorSurface.js +2 -2
  152. package/vue/chunks/UiEditorTableContextMenu.js +2 -2
  153. package/vue/chunks/UiEditorTableOverlay.js +2 -2
  154. package/vue/chunks/UiEditorTableToolbar.js +2 -2
  155. package/vue/chunks/UiEditorToolbar.js +2 -2
  156. package/vue/chunks/UiFloatingActionButton.js +2 -2
  157. package/vue/chunks/UiFormField.js +2 -2
  158. package/vue/chunks/UiGrid.js +2 -2
  159. package/vue/chunks/UiIcon.js +2 -2
  160. package/vue/chunks/UiIconButton.js +77 -11
  161. package/vue/chunks/UiImage.js +2 -2
  162. package/vue/chunks/UiInput.js +2 -2
  163. package/vue/chunks/UiInputGroup.js +2 -2
  164. package/vue/chunks/UiList.js +2 -2
  165. package/vue/chunks/UiListItem.js +2 -2
  166. package/vue/chunks/UiListbox.js +2 -2
  167. package/vue/chunks/UiMenu.js +3 -3
  168. package/vue/chunks/UiMenuGroup.js +2 -2
  169. package/vue/chunks/UiMenuItem.js +2 -2
  170. package/vue/chunks/UiMeter.js +2 -2
  171. package/vue/chunks/UiNavItem.js +2 -2
  172. package/vue/chunks/UiNumberInput.js +390 -0
  173. package/vue/chunks/UiPageHeader.js +2 -2
  174. package/vue/chunks/UiPopover.js +4 -4
  175. package/vue/chunks/UiRadio.js +2 -2
  176. package/vue/chunks/UiRadioGroup.js +2 -2
  177. package/vue/chunks/UiReel.js +2 -2
  178. package/vue/chunks/UiScrollArea.js +2 -2
  179. package/vue/chunks/UiSearchResultRow.js +2 -2
  180. package/vue/chunks/UiSearchShell.js +2 -2
  181. package/vue/chunks/UiSection.js +2 -2
  182. package/vue/chunks/UiSelect.js +2 -2
  183. package/vue/chunks/UiSeparator.js +2 -2
  184. package/vue/chunks/UiSidebar.js +2 -2
  185. package/vue/chunks/UiSlider.js +396 -0
  186. package/vue/chunks/UiSpinner.js +2 -2
  187. package/vue/chunks/UiStack.js +2 -2
  188. package/vue/chunks/UiStatusMessage.js +2 -2
  189. package/vue/chunks/UiSwatch.js +2 -2
  190. package/vue/chunks/UiSwitch.js +2 -2
  191. package/vue/chunks/UiSwitcher.js +2 -2
  192. package/vue/chunks/UiTable.js +2 -2
  193. package/vue/chunks/UiTabs.js +3 -3
  194. package/vue/chunks/UiText.js +53 -12
  195. package/vue/chunks/UiTextarea.js +2 -2
  196. package/vue/chunks/UiToast.js +2 -2
  197. package/vue/chunks/UiToastRegion.js +2 -2
  198. package/vue/chunks/UiTooltip.js +3 -3
  199. package/vue/chunks/UiTopBar.js +1 -1
  200. package/vue/chunks/UiTree.js +2 -2
  201. package/vue/chunks/UiTreeItem.js +2 -2
  202. package/vue/chunks/_plugin-vue_export-helper.js +68 -2
  203. package/vue/chunks/props.js +24 -1
  204. package/vue/components.css +2215 -1203
  205. package/vue/editor/index.js +623 -211
  206. package/vue/index.d.ts +3 -0
  207. package/vue/index.js +5 -2
@@ -0,0 +1,53 @@
1
+ import type { PropType } from 'vue';
2
+ import { type InputBindings } from './props.js';
3
+ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
4
+ disabled: {
5
+ type: PropType<boolean | null>;
6
+ };
7
+ label: {
8
+ type: PropType<string | null>;
9
+ };
10
+ size: {
11
+ type: PropType<"sm" | "md" | "lg" | null>;
12
+ };
13
+ value: {
14
+ type: PropType<string | null>;
15
+ };
16
+ "\0htmlNextInputStatus": {
17
+ type: PropType<InputBindings>;
18
+ };
19
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
20
+ input: (event: CustomEvent<{
21
+ readonly value: string;
22
+ }>) => any;
23
+ change: (event: CustomEvent<{
24
+ readonly value: string;
25
+ }>) => any;
26
+ "update:value": (value: string) => any;
27
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
28
+ disabled: {
29
+ type: PropType<boolean | null>;
30
+ };
31
+ label: {
32
+ type: PropType<string | null>;
33
+ };
34
+ size: {
35
+ type: PropType<"sm" | "md" | "lg" | null>;
36
+ };
37
+ value: {
38
+ type: PropType<string | null>;
39
+ };
40
+ "\0htmlNextInputStatus": {
41
+ type: PropType<InputBindings>;
42
+ };
43
+ }>> & Readonly<{
44
+ onInput?: ((event: CustomEvent<{
45
+ readonly value: string;
46
+ }>) => any) | undefined;
47
+ onChange?: ((event: CustomEvent<{
48
+ readonly value: string;
49
+ }>) => any) | undefined;
50
+ "onUpdate:value"?: ((value: string) => any) | undefined;
51
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
52
+ declare const _default: typeof __VLS_export;
53
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import { t as UiCurveEditor_default } from "./chunks/UiCurveEditor.js";
2
+ export { UiCurveEditor_default as default };
@@ -0,0 +1,427 @@
1
+ <!-- Generated by HTML Next 1.0.0-alpha.69 for Vue 3.5. Do not edit. -->
2
+ <script setup lang="ts">
3
+ import { computed, getCurrentInstance, provide, ref, useTemplateRef, watchSyncEffect } from 'vue'
4
+ import type { PropType } from 'vue'
5
+ import {
6
+ checkHydratedRoot,
7
+ createDispatch,
8
+ nativeAttrs,
9
+ useComponentHost,
10
+ useReflectedProp,
11
+ } from './host'
12
+ import { acceptsControllerWrite } from './props'
13
+ import {
14
+ BINDING_INPUTS_PROP,
15
+ checkedProp,
16
+ checkPropInput,
17
+ type InputBindings,
18
+ propValidityState,
19
+ READY_INPUT,
20
+ requireInputStatus,
21
+ UNRESOLVED_INPUT,
22
+ vPropValidity,
23
+ vuePropInputs,
24
+ } from './props'
25
+ import UiNumberInput from './UiNumberInput.vue'
26
+
27
+ defineOptions({ inheritAttrs: false })
28
+
29
+ const propValidityContract = {
30
+ props: {
31
+ disabled: {
32
+ type: { kind: 'terminal', name: 'boolean' },
33
+ required: false,
34
+ target: { attribute: 'disabled' },
35
+ description:
36
+ 'Prevents typing, stepping and pointer or keyboard changes while keeping the value visible.',
37
+ default: false,
38
+ },
39
+ label: {
40
+ type: { kind: 'terminal', name: 'string' },
41
+ required: false,
42
+ target: { attribute: 'aria-label' },
43
+ description: 'Accessible name for the editing control.',
44
+ default: 'Value',
45
+ },
46
+ size: {
47
+ type: { kind: 'terminal', name: 'keyword' },
48
+ required: false,
49
+ target: { attribute: 'size' },
50
+ description: 'Shared field and button height.',
51
+ values: ['sm', 'md', 'lg'],
52
+ default: 'md',
53
+ },
54
+ value: {
55
+ type: { kind: 'terminal', name: 'string' },
56
+ required: false,
57
+ target: { attribute: 'value' },
58
+ description:
59
+ 'CSS cubic-bezier or a standard easing keyword. X stays within 0–1; Y is bounded to -1–2 for a limited overshoot.',
60
+ default: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
61
+ },
62
+ },
63
+ } as const
64
+ const props = defineProps({
65
+ disabled: { type: null as unknown as PropType<boolean | null> },
66
+ label: { type: null as unknown as PropType<string | null> },
67
+ size: { type: null as unknown as PropType<'sm' | 'md' | 'lg' | null> },
68
+ value: { type: null as unknown as PropType<string | null> },
69
+ [BINDING_INPUTS_PROP]: { type: null as unknown as PropType<InputBindings> },
70
+ })
71
+ const acceptedProps: Record<string, unknown> = {
72
+ disabled: false,
73
+ label: 'Value',
74
+ size: 'md',
75
+ value: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
76
+ }
77
+ const inputTracking = vuePropInputs(acceptedProps, {
78
+ disabled: false,
79
+ label: 'Value',
80
+ size: 'md',
81
+ value: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
82
+ }, (name, value, source, values) => {
83
+ switch (name) {
84
+ case 'disabled':
85
+ return checkPropInput(value, { kind: 'terminal', name: 'boolean' }, true, true)
86
+ case 'label':
87
+ return checkPropInput(value, { kind: 'terminal', name: 'string' }, true, true)
88
+ case 'size':
89
+ return checkPropInput(value, { kind: 'terminal', name: 'keyword' }, true, true)
90
+ case 'value':
91
+ return checkPropInput(value, { kind: 'terminal', name: 'string' }, true, true)
92
+ default:
93
+ return { ok: false }
94
+ }
95
+ }, () => {
96
+ void checkedProps.value
97
+ })
98
+ const propInputs = inputTracking.inputs
99
+ const checkedProps = computed(() => {
100
+ void inputTracking.version.value
101
+ return ({
102
+ disabled: propInputs.value<boolean | null>(
103
+ 'disabled',
104
+ props['disabled'],
105
+ props[BINDING_INPUTS_PROP],
106
+ ) as boolean,
107
+ label: propInputs.value<string | null>(
108
+ 'label',
109
+ props['label'],
110
+ props[BINDING_INPUTS_PROP],
111
+ ) as string,
112
+ size: propInputs.value<'sm' | 'md' | 'lg' | null>(
113
+ 'size',
114
+ props['size'],
115
+ props[BINDING_INPUTS_PROP],
116
+ ) as 'sm' | 'md' | 'lg',
117
+ value: propInputs.value<string | null>(
118
+ 'value',
119
+ props['value'],
120
+ props[BINDING_INPUTS_PROP],
121
+ ) as string,
122
+ })
123
+ })
124
+ const inputStatus = (name: string, handlesError: boolean) => {
125
+ void checkedProps.value
126
+ void inputTracking.version.value
127
+ return requireInputStatus(propInputs.status(name), handlesError)
128
+ }
129
+ void checkedProps.value
130
+ watchSyncEffect(() => {
131
+ void checkedProps.value
132
+ })
133
+ const reflectedProp = useReflectedProp()
134
+ const hydrationInstance = getCurrentInstance()
135
+ const emit = defineEmits<{
136
+ 'update:value': [value: string]
137
+ input: [event: CustomEvent<{ readonly value: string }>]
138
+ change: [event: CustomEvent<{ readonly value: string }>]
139
+ }>()
140
+
141
+ const root = ref<HTMLElement | null>(null)
142
+ const plotElement = useTemplateRef<HTMLElement>('plotElement')
143
+ const firstLineElement = useTemplateRef<HTMLElement>('firstLineElement')
144
+ const secondLineElement = useTemplateRef<HTMLElement>('secondLineElement')
145
+ const curveElement = useTemplateRef<HTMLElement>('curveElement')
146
+ const firstElement = useTemplateRef<HTMLElement>('firstElement')
147
+ const secondElement = useTemplateRef<HTMLElement>('secondElement')
148
+ const resultElement = useTemplateRef<HTMLElement>('resultElement')
149
+ const point0 = ref('0.25')
150
+ const point1 = ref('0.1')
151
+ const point2 = ref('0.25')
152
+ const point3 = ref('1')
153
+ provide('html-next:ui-curve-editor:point0', point0)
154
+ provide('html-next:ui-curve-editor:point1', point1)
155
+ provide('html-next:ui-curve-editor:point2', point2)
156
+ provide('html-next:ui-curve-editor:point3', point3)
157
+ checkHydratedRoot('span', 'ui-curve-editor')
158
+
159
+ const isInputDetail = (
160
+ detail: unknown,
161
+ ): boolean => (detail !== null && typeof detail === 'object' && !Array.isArray(detail)
162
+ && typeof (detail as Record<string, unknown>)['value'] === 'string'
163
+ && Object.keys(detail as object).every((key) => ['value'].includes(key)))
164
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
165
+ checks: {
166
+ input: isInputDetail,
167
+ change: isInputDetail,
168
+ },
169
+ modeled: ['value'],
170
+ })
171
+
172
+ useComponentHost(() => import('../components/ui-curve-editor/ui-curve-editor.js'), {
173
+ root,
174
+ module: true,
175
+ dispatch,
176
+ acceptsState: (name: string, keys: readonly string[], value: unknown) =>
177
+ acceptsControllerWrite(
178
+ value,
179
+ ({
180
+ point0: { kind: 'terminal', name: 'string' },
181
+ point1: { kind: 'terminal', name: 'string' },
182
+ point2: { kind: 'terminal', name: 'string' },
183
+ point3: { kind: 'terminal', name: 'string' },
184
+ } as Record<string, any>)[name],
185
+ keys,
186
+ ),
187
+ initials: { point0: '0.25', point1: '0.1', point2: '0.25', point3: '1' },
188
+ controllerSource: {
189
+ specifier: '../components/ui-curve-editor/ui-curve-editor.js',
190
+ definition: './components/ui-curve-editor/ui-curve-editor.html',
191
+ },
192
+ props: checkedProps,
193
+ inputs: propInputs,
194
+ inputTracking,
195
+ propInputs: (name: string) => {
196
+ const incoming = hydrationInstance?.vnode.props
197
+ const kebab = name.replace(/[A-Z]/g, (letter) => '-' + letter.toLowerCase())
198
+ return incoming !== null && incoming !== undefined
199
+ ? (incoming[name] ?? incoming[kebab] ?? null)
200
+ : null
201
+ },
202
+ propNames: ['disabled', 'label', 'size', 'value'],
203
+ propValidity: (name: string) =>
204
+ propValidityState({ contract: propValidityContract, values: { ...props } }, name),
205
+ refs: {
206
+ plot: plotElement,
207
+ firstLine: firstLineElement,
208
+ secondLine: secondLineElement,
209
+ curve: curveElement,
210
+ first: firstElement,
211
+ second: secondElement,
212
+ result: resultElement,
213
+ },
214
+ state: { point0, point1, point2, point3 },
215
+ })
216
+ </script>
217
+
218
+ <template>
219
+ <span
220
+ class="ui-curve-editor"
221
+ v-bind="nativeAttrs($attrs)"
222
+ data-hn
223
+ v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
224
+ :data-ui-curve-editor-prop-disabled="reflectedProp('disabled', 'disabled', checkedProps.disabled, undefined, false)"
225
+ :data-ui-curve-editor-prop-label="reflectedProp('label', 'label', checkedProps.label, undefined, false)"
226
+ :data-ui-curve-editor-prop-size="reflectedProp('size', 'size', checkedProps.size, undefined, false)"
227
+ :data-ui-curve-editor-prop-value="reflectedProp('value', 'value', checkedProps.value, undefined, false)"
228
+ ref="root"
229
+ ><span class="plot-frame" role="group" :aria-label="checkedProps.label ?? undefined"><span
230
+ class="plot"
231
+ ref="plotElement"
232
+ ><svg viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true">
233
+ <path class="guide" d="M0 66.667 H100 M0 33.333 H100"></path>
234
+ <path class="guide" d="M0 66.667 L25 63.333" ref="firstLineElement"></path>
235
+ <path class="guide" d="M100 33.333 L25 33.333" ref="secondLineElement"></path>
236
+ <path d="M0 66.667 C25 63.333 25 33.333 100 33.333" ref="curveElement"></path>
237
+ </svg>{{ ' ' }}<button
238
+ class="handle"
239
+ type="button"
240
+ aria-label="First curve handle. Arrow keys adjust; Shift moves faster."
241
+ :disabled="checkedProps.disabled ?? undefined"
242
+ ref="firstElement"
243
+ >
244
+ </button>{{ ' ' }}<button
245
+ class="handle second"
246
+ type="button"
247
+ aria-label="Second curve handle. Arrow keys adjust; Shift moves faster."
248
+ :disabled="checkedProps.disabled ?? undefined"
249
+ ref="secondElement"
250
+ >
251
+ </button></span></span>{{ ' ' }}<span class="coordinates"><span class="coordinate"><span
252
+ >X1</span>
253
+ <UiNumberInput
254
+ class="ui-number-input"
255
+ data-curve-coordinate="0"
256
+ :min="0"
257
+ :max="1"
258
+ :step="0.01"
259
+ label="First handle X"
260
+ :value="point0"
261
+ :size="checkedProps.size"
262
+ :disabled="checkedProps.disabled"
263
+ v-bind="{
264
+ [BINDING_INPUTS_PROP]: {
265
+ size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
266
+ disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
267
+ },
268
+ }"
269
+ /></span>{{ ' ' }}<span class="coordinate"><span>Y1</span>
270
+ <UiNumberInput
271
+ class="ui-number-input"
272
+ data-curve-coordinate="1"
273
+ :min="-1"
274
+ :max="2"
275
+ :step="0.01"
276
+ label="First handle Y"
277
+ :value="point1"
278
+ :size="checkedProps.size"
279
+ :disabled="checkedProps.disabled"
280
+ v-bind="{
281
+ [BINDING_INPUTS_PROP]: {
282
+ size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
283
+ disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
284
+ },
285
+ }"
286
+ /></span>{{ ' ' }}<span class="coordinate"><span>X2</span>
287
+ <UiNumberInput
288
+ class="ui-number-input"
289
+ data-curve-coordinate="2"
290
+ :min="0"
291
+ :max="1"
292
+ :step="0.01"
293
+ label="Second handle X"
294
+ :value="point2"
295
+ :size="checkedProps.size"
296
+ :disabled="checkedProps.disabled"
297
+ v-bind="{
298
+ [BINDING_INPUTS_PROP]: {
299
+ size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
300
+ disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
301
+ },
302
+ }"
303
+ /></span>{{ ' ' }}<span class="coordinate"><span>Y2</span>
304
+ <UiNumberInput
305
+ class="ui-number-input"
306
+ data-curve-coordinate="3"
307
+ :min="-1"
308
+ :max="2"
309
+ :step="0.01"
310
+ label="Second handle Y"
311
+ :value="point3"
312
+ :size="checkedProps.size"
313
+ :disabled="checkedProps.disabled"
314
+ v-bind="{
315
+ [BINDING_INPUTS_PROP]: {
316
+ size: () => ({ value: checkedProps.size, status: inputStatus('size', true) }),
317
+ disabled: () => ({ value: checkedProps.disabled, status: inputStatus('disabled', true) }),
318
+ },
319
+ }"
320
+ /></span></span>{{ ' ' }}<output ref="resultElement">{{
321
+ checkedProps.value
322
+ }}</output></span>
323
+ </template>
324
+
325
+ <style scoped>
326
+ @scope (.ui-curve-editor) to ([data-hn]) {
327
+ :global(:scope) {
328
+ display: grid !important;
329
+ gap: var(--ui-space-3) !important;
330
+ margin: 0 !important;
331
+ padding: 0 !important;
332
+ min-inline-size: 0;
333
+ }
334
+ :global(.plot-frame) {
335
+ box-sizing: border-box !important;
336
+ display: block !important;
337
+ block-size: 12rem;
338
+ padding: max(var(--ui-space-4), 0.75rem, calc(var(--ui-control-min-block-size) / 2)) !important;
339
+ margin: 0 !important;
340
+ border: var(--ui-border-width) solid var(--ui-control-border);
341
+ border-radius: var(--ui-field-radius, var(--ui-radius-md));
342
+ background: var(--ui-control-surface, var(--ui-surface));
343
+ }
344
+ :global(.plot) {
345
+ position: relative;
346
+ display: block !important;
347
+ inline-size: 100%;
348
+ block-size: 100%;
349
+ }
350
+ :global(svg) {
351
+ inline-size: 100%;
352
+ block-size: 100%;
353
+ overflow: visible;
354
+ }
355
+ :global(path) {
356
+ fill: none;
357
+ stroke: var(--ui-accent-solid);
358
+ stroke-width: 2;
359
+ vector-effect: non-scaling-stroke;
360
+ }
361
+ :global(.guide) {
362
+ stroke: var(--ui-control-border);
363
+ stroke-width: 1;
364
+ }
365
+ :global(.handle) {
366
+ position: absolute;
367
+ left: 25%;
368
+ top: 63.333%;
369
+ translate: -50% -50%;
370
+ inline-size: max(1.5rem, var(--ui-control-min-block-size));
371
+ block-size: max(1.5rem, var(--ui-control-min-block-size));
372
+ border: 0;
373
+ border-radius: 50%;
374
+ background: transparent;
375
+ color: var(--ui-text-primary);
376
+ touch-action: none;
377
+ cursor: grab;
378
+ padding: 0 !important;
379
+ margin: 0 !important;
380
+ }
381
+ :global(.second) {
382
+ top: 33.333%;
383
+ }
384
+ :global(.handle::after) {
385
+ content: "";
386
+ position: absolute;
387
+ inset: 25%;
388
+ border: var(--ui-border-width) solid var(--ui-accent-solid);
389
+ background: var(--ui-surface-raised);
390
+ border-radius: 50%;
391
+ box-shadow: var(--ui-shadow-xs);
392
+ }
393
+ :global(.handle::before) {
394
+ content: "";
395
+ position: absolute;
396
+ inset: 40%;
397
+ background: var(--ui-accent-solid);
398
+ border-radius: 50%;
399
+ z-index: 1;
400
+ }
401
+ :global(.handle:focus-visible) {
402
+ outline: var(--ui-focus-width) solid var(--ui-control-focus, var(--ui-accent-solid));
403
+ outline-offset: var(--ui-space-1);
404
+ }
405
+ :global(.handle:disabled) {
406
+ cursor: not-allowed;
407
+ }
408
+ :global(.coordinates) {
409
+ display: grid !important;
410
+ grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
411
+ gap: var(--ui-space-2) !important;
412
+ }
413
+ :global(.coordinate) {
414
+ display: grid !important;
415
+ gap: var(--ui-space-1) !important;
416
+ font-size: var(--ui-font-size-sm);
417
+ }
418
+ :global(output) {
419
+ overflow-wrap: anywhere;
420
+ font-family: var(--ui-font-mono, monospace);
421
+ font-size: var(--ui-font-size-sm);
422
+ }
423
+ :global(:scope[hidden]) {
424
+ display: none !important;
425
+ }
426
+ }
427
+ </style>