@getdom/studio 0.1.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.
- package/LICENSE.md +109 -0
- package/README.md +44 -0
- package/SKILL.md +83 -0
- package/package.json +73 -0
- package/public/llms.txt +57 -0
- package/public/skills.sh +11 -0
- package/src/pages/_layout/componentCatalog.generated.js +4514 -0
- package/src/pages/_layout/componentInspector.js +60 -0
- package/src/pages/_layout/componentManager.js +192 -0
- package/src/pages/_layout/componentRuntimeRecords.js +49 -0
- package/src/pages/_layout/inspector/componentRegistry.js +639 -0
- package/src/pages/_layout/inspector/serialize.js +134 -0
- package/src/pages/_layout/inspector/useInspector.js +293 -0
- package/src/pages/components/accordion/DomAccordion.vue +39 -0
- package/src/pages/components/breadcrumbs/DomBreadcrumbs.vue +347 -0
- package/src/pages/components/button/DomButton.vue +132 -0
- package/src/pages/components/command-palette/DomCommandPalette.vue +482 -0
- package/src/pages/components/context-menu/DomContextMenu.vue +178 -0
- package/src/pages/components/dialog/DomDialog.vue +271 -0
- package/src/pages/components/dialog/DomDialogSchemaForm.vue +72 -0
- package/src/pages/components/dialog/DomDialogStack.vue +289 -0
- package/src/pages/components/dialog/useDialogs.js +253 -0
- package/src/pages/components/drawer/DomDrawer.vue +159 -0
- package/src/pages/components/dropdown/DomDropdown.vue +261 -0
- package/src/pages/components/icon-button/DomIconButton.vue +155 -0
- package/src/pages/components/lightbox/DomLightbox.vue +1561 -0
- package/src/pages/components/menu/DomMenu.vue +359 -0
- package/src/pages/components/menu/DomMenuItem.vue +233 -0
- package/src/pages/components/menu/DomMenuLabel.vue +19 -0
- package/src/pages/components/menu/DomMenuSeparator.vue +14 -0
- package/src/pages/components/menu/menuContext.js +11 -0
- package/src/pages/components/menu/menuPlacement.js +26 -0
- package/src/pages/components/menu/submenu.js +58 -0
- package/src/pages/components/pagination/DomPagination.vue +265 -0
- package/src/pages/components/playground/DomRenderer.vue +48 -0
- package/src/pages/components/popover/DomPopover.vue +244 -0
- package/src/pages/components/profile-menu/DomProfileMenu.vue +408 -0
- package/src/pages/components/profile-menu/DomProfileMenuItemContent.vue +45 -0
- package/src/pages/components/scroll-menu/DomScrollMenu.vue +430 -0
- package/src/pages/components/scroll-menu/DomScrollMenuItem.vue +212 -0
- package/src/pages/components/scroll-menu/scrollMenuContext.js +22 -0
- package/src/pages/components/splitter-panel/DomSplitterPanel.vue +283 -0
- package/src/pages/components/stepper/DomStepper.vue +386 -0
- package/src/pages/components/tabs/DomTabs.vue +149 -0
- package/src/pages/components/theme-switcher/DomThemeSwitcher.vue +226 -0
- package/src/pages/components/toast/DomToastItem.vue +52 -0
- package/src/pages/components/toast/DomToastStack.vue +768 -0
- package/src/pages/components/toast/useToasts.js +237 -0
- package/src/pages/components/toolbar/DomToolbar.vue +158 -0
- package/src/pages/components/tooltip/DomTooltip.vue +69 -0
- package/src/pages/components/tooltip/vDomTooltip.js +106 -0
- package/src/pages/components/tree-view/DomTreeView.vue +961 -0
- package/src/pages/components/tree-view/treeSchemas.js +129 -0
- package/src/pages/components/tree-view/treeUtils.js +228 -0
- package/src/pages/data/_shared/calculateVirtualWindow.js +101 -0
- package/src/pages/data/_shared/resourceRecord.js +29 -0
- package/src/pages/data/activity-timeline/DomActivityTimeline.vue +417 -0
- package/src/pages/data/agent-chat/DomAgentChatShell.vue +565 -0
- package/src/pages/data/agent-chat/DomAgentConversation.vue +737 -0
- package/src/pages/data/agent-chat/DomAgentConversationList.vue +319 -0
- package/src/pages/data/agent-chat/examples/agentChatMockApi.js +620 -0
- package/src/pages/data/agent-chat/examples/useAgentChatDemoStore.js +730 -0
- package/src/pages/data/data-grid/DataGridVirtualRows.vue +220 -0
- package/src/pages/data/data-grid/DomDataGrid.vue +1643 -0
- package/src/pages/data/document-editor/DomDocumentEditor.vue +3030 -0
- package/src/pages/data/document-editor/documentEditorCodeBlock.js +282 -0
- package/src/pages/data/document-editor/examples/documentEditorMockApi.js +272 -0
- package/src/pages/data/document-editor/examples/useDocumentEditorDemoStore.js +284 -0
- package/src/pages/data/filter-bar/DomFilterBar.vue +533 -0
- package/src/pages/data/kanban/DomKanban.vue +1703 -0
- package/src/pages/data/kanban/kanbanApi.js +80 -0
- package/src/pages/data/media-browser/DomMediaBrowser.vue +2344 -0
- package/src/pages/data/media-browser/examples/mediaBrowserMockApi.js +653 -0
- package/src/pages/data/media-browser/examples/useMediaBrowserDemoStore.js +1157 -0
- package/src/pages/data/month-calendar/DomMonthCalendar.vue +1718 -0
- package/src/pages/data/week-planner/DomWeekPlanner.vue +2308 -0
- package/src/pages/dev/code-block/DomCodeBlock.vue +263 -0
- package/src/pages/dev/json-viewer/DomJsonViewer.vue +962 -0
- package/src/pages/forms/_shared/DomFieldLoadingSpinner.vue +12 -0
- package/src/pages/forms/_shared/options.js +61 -0
- package/src/pages/forms/_shared/useOptionMenu.js +59 -0
- package/src/pages/forms/autocomplete/DomAutocomplete.vue +180 -0
- package/src/pages/forms/calendar/DomCalendar.vue +442 -0
- package/src/pages/forms/checkbox/DomCheckbox.vue +69 -0
- package/src/pages/forms/class-toggle-input/DomClassToggleInput.vue +316 -0
- package/src/pages/forms/code-input/DomCodeInput.vue +202 -0
- package/src/pages/forms/color-input/DomColorInput.vue +118 -0
- package/src/pages/forms/combobox/DomCombobox.vue +237 -0
- package/src/pages/forms/confirmation-code-input/DomConfirmationCodeInput.vue +345 -0
- package/src/pages/forms/date-picker/DomDatePicker.vue +299 -0
- package/src/pages/forms/date-time-picker/DomDateTimePicker.vue +630 -0
- package/src/pages/forms/email-input/DomEmailInput.vue +55 -0
- package/src/pages/forms/field/DomField.vue +267 -0
- package/src/pages/forms/field/fieldLayout.js +1 -0
- package/src/pages/forms/field/fieldProps.js +114 -0
- package/src/pages/forms/field/layouts/DomGridFieldLayout.vue +38 -0
- package/src/pages/forms/field/useField.js +343 -0
- package/src/pages/forms/field/validators.js +364 -0
- package/src/pages/forms/file-upload/DomFileUpload.vue +361 -0
- package/src/pages/forms/form/DomForm.vue +985 -0
- package/src/pages/forms/form/adapters/fieldBuilder.js +45 -0
- package/src/pages/forms/form/adapters/jsonSchema.js +264 -0
- package/src/pages/forms/form/adapters/shared.js +53 -0
- package/src/pages/forms/form/adapters/zod.js +235 -0
- package/src/pages/forms/form/formApi.js +38 -0
- package/src/pages/forms/form/formDefinition.js +392 -0
- package/src/pages/forms/form/schemaAdapter.js +54 -0
- package/src/pages/forms/icon-selector/DomIconSelector.vue +460 -0
- package/src/pages/forms/icon-selector/iconSelectorItems.js +490 -0
- package/src/pages/forms/input-group/DomInputGroup.vue +232 -0
- package/src/pages/forms/json-input/DomJsonInput.vue +227 -0
- package/src/pages/forms/json-list-input/DomJsonListInput.vue +206 -0
- package/src/pages/forms/listbox/DomListbox.vue +105 -0
- package/src/pages/forms/money-input/DomMoneyInput.vue +147 -0
- package/src/pages/forms/native-select/DomNativeSelect.vue +67 -0
- package/src/pages/forms/number-input/DomNumberInput.vue +47 -0
- package/src/pages/forms/password-input/DomPasswordInput.vue +218 -0
- package/src/pages/forms/password-input/pwnedPasswords.js +47 -0
- package/src/pages/forms/password-strength/DomPasswordStrength.vue +128 -0
- package/src/pages/forms/password-strength/passwordStrength.js +92 -0
- package/src/pages/forms/position-input/DomPositionInput.vue +83 -0
- package/src/pages/forms/radio-group/DomRadioGroup.vue +102 -0
- package/src/pages/forms/range-input/DomRangeInput.vue +296 -0
- package/src/pages/forms/select/DomSelect.vue +479 -0
- package/src/pages/forms/select-input/DomSelectInput.vue +155 -0
- package/src/pages/forms/tag-combobox/DomTagCombobox.vue +358 -0
- package/src/pages/forms/text-input/DomTextInput.vue +48 -0
- package/src/pages/forms/textarea-composer/DomTextareaComposer.vue +234 -0
- package/src/pages/forms/textarea-input/DomTextareaInput.vue +86 -0
- package/src/pages/forms/textarea-input/useTextareaAutosize.js +147 -0
- package/src/pages/forms/time-selector/DomTimeSelector.vue +389 -0
- package/src/pages/forms/time-selector/timeUtils.js +194 -0
- package/src/pages/forms/toggle/DomToggle.vue +158 -0
- package/src/pages/forms/toggle-button/DomToggleButton.vue +88 -0
- package/src/pages/forms/toggle-button-group/DomToggleButtonGroup.vue +340 -0
- package/src/pages/forms/url-input/DomUrlInput.vue +55 -0
- package/src/pages/forms/wysiwyg/DomWysiwyg.vue +204 -0
- package/src/pages/lib/css/color.js +245 -0
- package/src/pages/lib/headless/accordion.d.ts +7 -0
- package/src/pages/lib/headless/accordion.js +246 -0
- package/src/pages/lib/headless/autocomplete.d.ts +4 -0
- package/src/pages/lib/headless/autocomplete.js +33 -0
- package/src/pages/lib/headless/base.d.ts +25 -0
- package/src/pages/lib/headless/base.js +127 -0
- package/src/pages/lib/headless/checkbox.d.ts +19 -0
- package/src/pages/lib/headless/checkbox.js +99 -0
- package/src/pages/lib/headless/combobox.d.ts +7 -0
- package/src/pages/lib/headless/combobox.js +488 -0
- package/src/pages/lib/headless/dialog.d.ts +23 -0
- package/src/pages/lib/headless/dialog.js +384 -0
- package/src/pages/lib/headless/drawer.d.ts +21 -0
- package/src/pages/lib/headless/drawer.js +682 -0
- package/src/pages/lib/headless/dropdown.d.ts +19 -0
- package/src/pages/lib/headless/dropdown.js +412 -0
- package/src/pages/lib/headless/floating-effect.js +118 -0
- package/src/pages/lib/headless/floating.d.ts +34 -0
- package/src/pages/lib/headless/floating.js +382 -0
- package/src/pages/lib/headless/index.d.ts +19 -0
- package/src/pages/lib/headless/index.js +19 -0
- package/src/pages/lib/headless/listbox.d.ts +19 -0
- package/src/pages/lib/headless/listbox.js +126 -0
- package/src/pages/lib/headless/menu.d.ts +18 -0
- package/src/pages/lib/headless/menu.js +117 -0
- package/src/pages/lib/headless/popover-panel.d.ts +18 -0
- package/src/pages/lib/headless/popover-panel.js +309 -0
- package/src/pages/lib/headless/popover.d.ts +19 -0
- package/src/pages/lib/headless/popover.js +391 -0
- package/src/pages/lib/headless/radio-group.d.ts +19 -0
- package/src/pages/lib/headless/radio-group.js +100 -0
- package/src/pages/lib/headless/tabs.d.ts +18 -0
- package/src/pages/lib/headless/tabs.js +119 -0
- package/src/pages/lib/headless/toast.d.ts +13 -0
- package/src/pages/lib/headless/toast.js +65 -0
- package/src/pages/lib/headless/toggle.d.ts +19 -0
- package/src/pages/lib/headless/toggle.js +162 -0
- package/src/pages/lib/headless/tooltip-controller.d.ts +22 -0
- package/src/pages/lib/headless/tooltip-controller.js +549 -0
- package/src/pages/lib/headless/tooltip.d.ts +19 -0
- package/src/pages/lib/headless/tooltip.js +153 -0
- package/src/pages/lib/headless/transitions.d.ts +5 -0
- package/src/pages/lib/headless/transitions.js +89 -0
- package/src/pages/lib/vue/_internal/DomLiquidGlassSurface.vue +310 -0
- package/src/pages/lib/vue/_internal/liquidGlass.js +112 -0
- package/src/pages/lib/vue/_internal/liquidGlassConfig.js +10 -0
- package/src/pages/lib/vue/codeHighlighter.js +132 -0
- package/src/pages/lib/vue/floatingTeleportTarget.js +23 -0
- package/src/pages/lib/vue/index.d.ts +6806 -0
- package/src/pages/lib/vue/index.js +218 -0
- package/src/pages/lib/vue/useTheme.js +116 -0
- package/src/pages/mobile/action-sheet/DomActionSheet.vue +186 -0
- package/src/pages/mobile/bottom-nav/DomAppBottomNav.vue +94 -0
- package/src/pages/mobile/list-item/DomAppListItem.vue +90 -0
- package/src/pages/mobile/safe-area/DomSafeArea.vue +39 -0
- package/src/pages/mobile/shell/DomAppShell.vue +51 -0
- package/src/pages/mobile/stack/AppStackScreen.vue +63 -0
- package/src/pages/mobile/stack/DomAppStack.vue +711 -0
- package/src/pages/mobile/top-bar/DomAppTopBar.vue +67 -0
- package/src/pages/visual/alert/DomAlert.vue +363 -0
- package/src/pages/visual/avatar/DomAvatar.vue +110 -0
- package/src/pages/visual/avatar-stack/DomAvatarStack.vue +89 -0
- package/src/pages/visual/badge/DomBadge.vue +105 -0
- package/src/pages/visual/card/DomCard.vue +65 -0
- package/src/pages/visual/card-rail/DomCardRail.vue +99 -0
- package/src/pages/visual/empty-state/DomEmptyState.vue +88 -0
- package/src/pages/visual/progress/DomProgress.vue +212 -0
- package/src/pages/visual/progress/DomRadialProgress.vue +186 -0
- package/src/pages/visual/progress/DomSegmentedProgress.vue +350 -0
- package/src/pages/visual/skeleton/DomSkeleton.vue +174 -0
- package/src/pages/visual/spinner/DomSpinner.vue +122 -0
- package/src/pages/visual/status-pill/DomStatusPill.vue +75 -0
- package/src/pages/visual/text-diff/DomTextDiff.vue +577 -0
- package/src/pages/visual/text-diff/textDiff.js +300 -0
- package/src/style.css +446 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
const SIDE_OPTIONS = ['top', 'right', 'bottom', 'left'];
|
|
2
|
+
const ALIGN_OPTIONS = ['start', 'center', 'end'];
|
|
3
|
+
const FLOATING_MODES = ['viewport', 'anchor'];
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {'top' | 'right' | 'bottom' | 'left'} FloatingSide
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {'start' | 'center' | 'end' | 'left' | 'right'} FloatingAlign
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {'viewport' | 'anchor' | 'element'} FloatingMode
|
|
15
|
+
*
|
|
16
|
+
* `viewport` keeps the floating element inside the visible browser viewport by
|
|
17
|
+
* flipping and shifting when it would collide. `anchor` keeps the element
|
|
18
|
+
* attached to the requested side of the trigger, which is useful when a panel
|
|
19
|
+
* should scroll with its local context. `element` is kept as a backwards
|
|
20
|
+
* compatible alias for `anchor`.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} FloatingPositionOptions
|
|
25
|
+
* @property {`${FloatingSide}` | `${FloatingSide}-${'start' | 'center' | 'end'}`} [placement='bottom']
|
|
26
|
+
* Preferred side and optional alignment, such as `bottom-start`, `top-end`, or
|
|
27
|
+
* `right-center`.
|
|
28
|
+
* @property {FloatingAlign} [align='start']
|
|
29
|
+
* Fallback alignment when `placement` does not include one. `left` and `right`
|
|
30
|
+
* are normalized to `start` and `end`.
|
|
31
|
+
* @property {number} [offset=8]
|
|
32
|
+
* Gap in CSS pixels between the reference element and the floating element.
|
|
33
|
+
* @property {number} [padding=8]
|
|
34
|
+
* Collision padding in CSS pixels between the floating element and viewport.
|
|
35
|
+
* @property {FloatingMode} [mode='viewport']
|
|
36
|
+
* Positioning mode. `viewport` enables default flip and shift behavior.
|
|
37
|
+
* @property {FloatingMode} [floatingMode]
|
|
38
|
+
* Attribute-friendly alias for `mode`.
|
|
39
|
+
* @property {boolean} [flip]
|
|
40
|
+
* Whether to move to the opposite side when there is more space there.
|
|
41
|
+
* Defaults to true in `viewport` mode and false in `anchor` mode.
|
|
42
|
+
* @property {boolean} [shift]
|
|
43
|
+
* Whether to clamp coordinates inside the viewport bounds. Defaults to true in
|
|
44
|
+
* `viewport` mode and false in `anchor` mode.
|
|
45
|
+
* @property {'fixed' | 'absolute'} [strategy='fixed']
|
|
46
|
+
* CSS positioning strategy used by `applyFloatingPosition`.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @typedef {Object} FloatingPositionResult
|
|
51
|
+
* @property {number} x Final viewport x coordinate in CSS pixels.
|
|
52
|
+
* @property {number} y Final viewport y coordinate in CSS pixels.
|
|
53
|
+
* @property {'viewport' | 'anchor'} mode Normalized positioning mode.
|
|
54
|
+
* @property {FloatingSide} side Resolved side after optional flipping.
|
|
55
|
+
* @property {'start' | 'center' | 'end'} align Normalized alignment.
|
|
56
|
+
* @property {string} placement Resolved placement name, such as `bottom-start`.
|
|
57
|
+
* @property {boolean} flipped Whether the side changed from the requested side.
|
|
58
|
+
* @property {Record<FloatingSide, number>} collision Overflow measured before shifting.
|
|
59
|
+
* @property {FloatingSide[]} collisionSides Sides that collided before shifting.
|
|
60
|
+
* @property {Record<FloatingSide, number>} overflow Remaining overflow after shifting.
|
|
61
|
+
* @property {FloatingSide[]} overflowSides Sides still overflowing after shifting.
|
|
62
|
+
* @property {number} availableWidth Viewport width available inside collision padding.
|
|
63
|
+
* @property {number} availableHeight Space available on the resolved vertical side.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
function clamp(value, min, max) {
|
|
67
|
+
return Math.min(Math.max(value, min), max);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeAlign(value) {
|
|
71
|
+
if (value === 'left') return 'start';
|
|
72
|
+
if (value === 'right') return 'end';
|
|
73
|
+
return ALIGN_OPTIONS.includes(value) ? value : 'start';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeMode(value) {
|
|
77
|
+
if (value === 'element') return 'anchor';
|
|
78
|
+
return FLOATING_MODES.includes(value) ? value : 'viewport';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function parsePlacement(placement = 'bottom', align = 'start') {
|
|
82
|
+
const [rawSide, rawAlign] = String(placement).split('-');
|
|
83
|
+
return {
|
|
84
|
+
side: SIDE_OPTIONS.includes(rawSide) ? rawSide : 'bottom',
|
|
85
|
+
align: normalizeAlign(rawAlign || align),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function oppositeSide(side) {
|
|
90
|
+
return {
|
|
91
|
+
top: 'bottom',
|
|
92
|
+
right: 'left',
|
|
93
|
+
bottom: 'top',
|
|
94
|
+
left: 'right',
|
|
95
|
+
}[side] || 'bottom';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function getViewportRect(padding, view = window) {
|
|
99
|
+
const viewport = view.visualViewport;
|
|
100
|
+
const left = viewport ? viewport.offsetLeft : 0;
|
|
101
|
+
const top = viewport ? viewport.offsetTop : 0;
|
|
102
|
+
const width = viewport ? viewport.width : view.innerWidth;
|
|
103
|
+
const height = viewport ? viewport.height : view.innerHeight;
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
top: top + padding,
|
|
107
|
+
right: left + width - padding,
|
|
108
|
+
bottom: top + height - padding,
|
|
109
|
+
left: left + padding,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function overflowFor(x, y, width, height, bounds) {
|
|
114
|
+
return {
|
|
115
|
+
top: Math.max(bounds.top - y, 0),
|
|
116
|
+
right: Math.max((x + width) - bounds.right, 0),
|
|
117
|
+
bottom: Math.max((y + height) - bounds.bottom, 0),
|
|
118
|
+
left: Math.max(bounds.left - x, 0),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function hasOverflow(overflow) {
|
|
123
|
+
return Object.values(overflow).some((value) => value > 0);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function axisSpace(side, reference, bounds, offset) {
|
|
127
|
+
if (side === 'top') return reference.top - bounds.top - offset;
|
|
128
|
+
if (side === 'right') return bounds.right - reference.right - offset;
|
|
129
|
+
if (side === 'bottom') return bounds.bottom - reference.bottom - offset;
|
|
130
|
+
return reference.left - bounds.left - offset;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function baseCoords(side, align, reference, floating, offset) {
|
|
134
|
+
let x = reference.left;
|
|
135
|
+
let y = reference.bottom + offset;
|
|
136
|
+
|
|
137
|
+
if (side === 'top') y = reference.top - floating.height - offset;
|
|
138
|
+
if (side === 'right') x = reference.right + offset;
|
|
139
|
+
if (side === 'left') x = reference.left - floating.width - offset;
|
|
140
|
+
|
|
141
|
+
if (side === 'top' || side === 'bottom') {
|
|
142
|
+
if (align === 'center') x = reference.left + (reference.width / 2) - (floating.width / 2);
|
|
143
|
+
if (align === 'end') x = reference.right - floating.width;
|
|
144
|
+
} else {
|
|
145
|
+
y = reference.top;
|
|
146
|
+
if (align === 'center') y = reference.top + (reference.height / 2) - (floating.height / 2);
|
|
147
|
+
if (align === 'end') y = reference.bottom - floating.height;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { x, y };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getOverflowSides(overflow) {
|
|
154
|
+
return Object.entries(overflow)
|
|
155
|
+
.filter(([, value]) => value > 0)
|
|
156
|
+
.map(([side]) => side);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function rectWithLayoutSize(element) {
|
|
160
|
+
const rect = element.getBoundingClientRect();
|
|
161
|
+
const width = element.offsetWidth || rect.width;
|
|
162
|
+
const height = element.offsetHeight || rect.height;
|
|
163
|
+
return {
|
|
164
|
+
...rect,
|
|
165
|
+
width,
|
|
166
|
+
height,
|
|
167
|
+
right: rect.left + width,
|
|
168
|
+
bottom: rect.top + height,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function arrowContainer(floatingEl) {
|
|
173
|
+
return floatingEl.querySelector?.('.dom-popover-card') || floatingEl;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function getScrollParents(node) {
|
|
177
|
+
const parents = [];
|
|
178
|
+
const doc = node?.ownerDocument || document;
|
|
179
|
+
const view = doc.defaultView || window;
|
|
180
|
+
let parent = node?.parentElement;
|
|
181
|
+
|
|
182
|
+
while (parent && parent !== doc.body) {
|
|
183
|
+
const style = view.getComputedStyle(parent);
|
|
184
|
+
const overflow = `${style.overflow}${style.overflowX}${style.overflowY}`;
|
|
185
|
+
if (/(auto|scroll|overlay|hidden|clip)/.test(overflow)) parents.push(parent);
|
|
186
|
+
parent = parent.parentElement;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
parents.push(view);
|
|
190
|
+
return parents;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Measure where a floating element should sit relative to a reference element.
|
|
195
|
+
*
|
|
196
|
+
* The calculation is deliberately DOM-only and framework-neutral. It handles
|
|
197
|
+
* visual viewport offsets, viewport collision padding, optional side flipping,
|
|
198
|
+
* optional coordinate shifting, and dimensions from layout size so panels that
|
|
199
|
+
* have just moved into the top layer can still be measured accurately.
|
|
200
|
+
*
|
|
201
|
+
* Use this when you want coordinates and metadata but want to apply styles
|
|
202
|
+
* yourself. Use `applyFloatingPosition` when you want the helper to write the
|
|
203
|
+
* standard DOM Studio inline styles and data attributes for you.
|
|
204
|
+
*
|
|
205
|
+
* @param {Element} referenceEl The trigger, input, button, or anchor element.
|
|
206
|
+
* @param {HTMLElement} floatingEl The panel, menu, tooltip, or listbox element.
|
|
207
|
+
* @param {FloatingPositionOptions} [options]
|
|
208
|
+
* @returns {FloatingPositionResult | null} Position metadata, or null outside the browser.
|
|
209
|
+
*/
|
|
210
|
+
export function computeFloatingPosition(referenceEl, floatingEl, options = {}) {
|
|
211
|
+
const view = referenceEl?.ownerDocument?.defaultView;
|
|
212
|
+
if (!referenceEl || !floatingEl || !view) return null;
|
|
213
|
+
|
|
214
|
+
const {
|
|
215
|
+
placement = 'bottom',
|
|
216
|
+
align = 'start',
|
|
217
|
+
offset = 8,
|
|
218
|
+
padding = 8,
|
|
219
|
+
flip,
|
|
220
|
+
shift,
|
|
221
|
+
} = options;
|
|
222
|
+
const mode = normalizeMode(options.mode || options.floatingMode);
|
|
223
|
+
const shouldFlip = flip ?? mode === 'viewport';
|
|
224
|
+
const shouldShift = shift ?? mode === 'viewport';
|
|
225
|
+
const preferred = parsePlacement(placement, align);
|
|
226
|
+
const bounds = getViewportRect(Number(padding) || 0, view);
|
|
227
|
+
const reference = referenceEl.getBoundingClientRect();
|
|
228
|
+
const floating = rectWithLayoutSize(floatingEl);
|
|
229
|
+
let side = preferred.side;
|
|
230
|
+
const resolvedAlign = preferred.align;
|
|
231
|
+
|
|
232
|
+
let coords = baseCoords(side, resolvedAlign, reference, floating, Number(offset) || 0);
|
|
233
|
+
const initialOverflow = overflowFor(coords.x, coords.y, floating.width, floating.height, bounds);
|
|
234
|
+
|
|
235
|
+
if (shouldFlip && hasOverflow(initialOverflow)) {
|
|
236
|
+
const opposite = oppositeSide(side);
|
|
237
|
+
if (axisSpace(opposite, reference, bounds, Number(offset) || 0) > axisSpace(side, reference, bounds, Number(offset) || 0)) {
|
|
238
|
+
side = opposite;
|
|
239
|
+
coords = baseCoords(side, resolvedAlign, reference, floating, Number(offset) || 0);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let x = coords.x;
|
|
244
|
+
let y = coords.y;
|
|
245
|
+
|
|
246
|
+
if (shouldShift) {
|
|
247
|
+
x = clamp(x, bounds.left, Math.max(bounds.left, bounds.right - floating.width));
|
|
248
|
+
y = clamp(y, bounds.top, Math.max(bounds.top, bounds.bottom - floating.height));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const overflow = overflowFor(x, y, floating.width, floating.height, bounds);
|
|
252
|
+
const placementName = resolvedAlign === 'center' ? side : `${side}-${resolvedAlign}`;
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
x,
|
|
256
|
+
y,
|
|
257
|
+
mode,
|
|
258
|
+
side,
|
|
259
|
+
align: resolvedAlign,
|
|
260
|
+
placement: placementName,
|
|
261
|
+
flipped: side !== preferred.side,
|
|
262
|
+
collision: initialOverflow,
|
|
263
|
+
collisionSides: getOverflowSides(initialOverflow),
|
|
264
|
+
overflow,
|
|
265
|
+
overflowSides: getOverflowSides(overflow),
|
|
266
|
+
availableWidth: Math.max(bounds.right - bounds.left, 0),
|
|
267
|
+
availableHeight: Math.max(side === 'top'
|
|
268
|
+
? reference.top - bounds.top - (Number(offset) || 0)
|
|
269
|
+
: side === 'bottom'
|
|
270
|
+
? bounds.bottom - reference.bottom - (Number(offset) || 0)
|
|
271
|
+
: bounds.bottom - bounds.top, 0),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Position a floating element and expose placement metadata through attributes.
|
|
277
|
+
*
|
|
278
|
+
* This writes `position`, `top`, `left`, CSS custom properties for available
|
|
279
|
+
* size, popover arrow coordinates, and `data-*` attributes describing the final
|
|
280
|
+
* placement. DOM Studio popover, dropdown, combobox, autocomplete, tooltip, and
|
|
281
|
+
* menu surfaces all depend on this contract so styling can respond to placement
|
|
282
|
+
* without duplicating JavaScript.
|
|
283
|
+
*
|
|
284
|
+
* @param {Element} referenceEl The element the panel is anchored to.
|
|
285
|
+
* @param {HTMLElement} floatingEl The panel that should be moved.
|
|
286
|
+
* @param {FloatingPositionOptions} [options]
|
|
287
|
+
* @returns {FloatingPositionResult | null} The same result returned by `computeFloatingPosition`.
|
|
288
|
+
*/
|
|
289
|
+
export function applyFloatingPosition(referenceEl, floatingEl, options = {}) {
|
|
290
|
+
const result = computeFloatingPosition(referenceEl, floatingEl, options);
|
|
291
|
+
if (!result) return null;
|
|
292
|
+
|
|
293
|
+
floatingEl.style.position = options.strategy || 'fixed';
|
|
294
|
+
floatingEl.style.top = `${Math.round(result.y)}px`;
|
|
295
|
+
floatingEl.style.left = `${Math.round(result.x)}px`;
|
|
296
|
+
floatingEl.style.right = 'auto';
|
|
297
|
+
floatingEl.style.bottom = 'auto';
|
|
298
|
+
floatingEl.style.margin = '0';
|
|
299
|
+
floatingEl.style.transform = '';
|
|
300
|
+
floatingEl.style.setProperty('--dom-floating-available-width', `${Math.round(result.availableWidth)}px`);
|
|
301
|
+
floatingEl.style.setProperty('--dom-floating-available-height', `${Math.round(result.availableHeight)}px`);
|
|
302
|
+
const reference = referenceEl.getBoundingClientRect();
|
|
303
|
+
const arrowBox = arrowContainer(floatingEl);
|
|
304
|
+
const arrowOffsetX = arrowBox === floatingEl ? 0 : arrowBox.offsetLeft || 0;
|
|
305
|
+
const arrowOffsetY = arrowBox === floatingEl ? 0 : arrowBox.offsetTop || 0;
|
|
306
|
+
const arrowWidth = arrowBox.offsetWidth || floatingEl.offsetWidth || floatingEl.getBoundingClientRect().width;
|
|
307
|
+
const arrowHeight = arrowBox.offsetHeight || floatingEl.offsetHeight || floatingEl.getBoundingClientRect().height;
|
|
308
|
+
floatingEl.style.setProperty('--dom-popover-arrow-x', `${Math.round(clamp(
|
|
309
|
+
(reference.left + (reference.width / 2)) - result.x - arrowOffsetX,
|
|
310
|
+
14,
|
|
311
|
+
Math.max(14, arrowWidth - 14),
|
|
312
|
+
))}px`);
|
|
313
|
+
floatingEl.style.setProperty('--dom-popover-arrow-y', `${Math.round(clamp(
|
|
314
|
+
(reference.top + (reference.height / 2)) - result.y - arrowOffsetY,
|
|
315
|
+
14,
|
|
316
|
+
Math.max(14, arrowHeight - 14),
|
|
317
|
+
))}px`);
|
|
318
|
+
floatingEl.dataset.placement = result.placement;
|
|
319
|
+
floatingEl.dataset.floatingMode = result.mode;
|
|
320
|
+
floatingEl.dataset.side = result.side;
|
|
321
|
+
floatingEl.dataset.align = result.align;
|
|
322
|
+
floatingEl.toggleAttribute('data-flipped', result.flipped);
|
|
323
|
+
|
|
324
|
+
for (const side of SIDE_OPTIONS) {
|
|
325
|
+
floatingEl.toggleAttribute(`data-collision-${side}`, result.collision[side] > 0);
|
|
326
|
+
floatingEl.toggleAttribute(`data-overflow-${side}`, result.overflow[side] > 0);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Re-run a positioning callback when layout conditions change.
|
|
334
|
+
*
|
|
335
|
+
* The helper watches scroll parents for both the anchor and panel, browser
|
|
336
|
+
* resize, visual viewport movement, and element resize. Updates are batched in
|
|
337
|
+
* `requestAnimationFrame` so rapid scroll and resize bursts only trigger one
|
|
338
|
+
* positioning pass per frame.
|
|
339
|
+
*
|
|
340
|
+
* @param {Element} referenceEl The element used as the positioning anchor.
|
|
341
|
+
* @param {HTMLElement} floatingEl The floating panel being observed.
|
|
342
|
+
* @param {() => void} update Callback that recomputes or reapplies position.
|
|
343
|
+
* @returns {() => void} Cleanup function that removes listeners and observers.
|
|
344
|
+
*/
|
|
345
|
+
export function autoUpdateFloating(referenceEl, floatingEl, update) {
|
|
346
|
+
const view = referenceEl?.ownerDocument?.defaultView;
|
|
347
|
+
if (!referenceEl || !floatingEl || !view) return () => {};
|
|
348
|
+
|
|
349
|
+
let frame = 0;
|
|
350
|
+
const requestUpdate = () => {
|
|
351
|
+
if (frame) return;
|
|
352
|
+
frame = view.requestAnimationFrame(() => {
|
|
353
|
+
frame = 0;
|
|
354
|
+
update();
|
|
355
|
+
});
|
|
356
|
+
};
|
|
357
|
+
const parents = new Set([
|
|
358
|
+
...getScrollParents(referenceEl),
|
|
359
|
+
...getScrollParents(floatingEl),
|
|
360
|
+
]);
|
|
361
|
+
const viewport = view.visualViewport;
|
|
362
|
+
const resizeObserver = 'ResizeObserver' in view
|
|
363
|
+
? new view.ResizeObserver(requestUpdate)
|
|
364
|
+
: null;
|
|
365
|
+
|
|
366
|
+
for (const parent of parents) parent.addEventListener('scroll', requestUpdate, { passive: true });
|
|
367
|
+
view.addEventListener('resize', requestUpdate);
|
|
368
|
+
viewport?.addEventListener('resize', requestUpdate);
|
|
369
|
+
viewport?.addEventListener('scroll', requestUpdate);
|
|
370
|
+
resizeObserver?.observe(referenceEl);
|
|
371
|
+
resizeObserver?.observe(floatingEl);
|
|
372
|
+
requestUpdate();
|
|
373
|
+
|
|
374
|
+
return () => {
|
|
375
|
+
if (frame) view.cancelAnimationFrame(frame);
|
|
376
|
+
for (const parent of parents) parent.removeEventListener('scroll', requestUpdate);
|
|
377
|
+
view.removeEventListener('resize', requestUpdate);
|
|
378
|
+
viewport?.removeEventListener('resize', requestUpdate);
|
|
379
|
+
viewport?.removeEventListener('scroll', requestUpdate);
|
|
380
|
+
resizeObserver?.disconnect();
|
|
381
|
+
};
|
|
382
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// Generated by scripts/generate-types.mjs. Do not edit by hand.
|
|
3
|
+
export * from './base.js';
|
|
4
|
+
export * from './floating.js';
|
|
5
|
+
export * from './dropdown.js';
|
|
6
|
+
export * from './dialog.js';
|
|
7
|
+
export * from './popover.js';
|
|
8
|
+
export * from './tabs.js';
|
|
9
|
+
export * from './toggle.js';
|
|
10
|
+
export * from './checkbox.js';
|
|
11
|
+
export * from './radio-group.js';
|
|
12
|
+
export * from './tooltip.js';
|
|
13
|
+
export * from './accordion.js';
|
|
14
|
+
export * from './menu.js';
|
|
15
|
+
export * from './listbox.js';
|
|
16
|
+
export * from './combobox.js';
|
|
17
|
+
export * from './autocomplete.js';
|
|
18
|
+
export * from './drawer.js';
|
|
19
|
+
export * from './toast.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Register every DOM Studio custom element. Importing this module is enough
|
|
2
|
+
// to make <dom-dropdown>, <dom-dialog>, etc. work in any page.
|
|
3
|
+
export * from './base.js';
|
|
4
|
+
export * from './floating.js';
|
|
5
|
+
export * from './dropdown.js';
|
|
6
|
+
export * from './dialog.js';
|
|
7
|
+
export * from './popover.js';
|
|
8
|
+
export * from './tabs.js';
|
|
9
|
+
export * from './toggle.js';
|
|
10
|
+
export * from './checkbox.js';
|
|
11
|
+
export * from './radio-group.js';
|
|
12
|
+
export * from './tooltip.js';
|
|
13
|
+
export * from './accordion.js';
|
|
14
|
+
export * from './menu.js';
|
|
15
|
+
export * from './listbox.js';
|
|
16
|
+
export * from './combobox.js';
|
|
17
|
+
export * from './autocomplete.js';
|
|
18
|
+
export * from './drawer.js';
|
|
19
|
+
export * from './toast.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// Generated by scripts/generate-types.mjs. Do not edit by hand.
|
|
3
|
+
import { DomElementBase } from './base.js';
|
|
4
|
+
export declare class DomListboxElement extends DomElementBase {
|
|
5
|
+
static readonly observedAttributes?: Array<string>;
|
|
6
|
+
static readonly __doc?: HeadlessElementDoc;
|
|
7
|
+
value: string;
|
|
8
|
+
readonly options: Array<HTMLElement>;
|
|
9
|
+
}
|
|
10
|
+
export interface HeadlessElementDoc {
|
|
11
|
+
name?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
slots?: Array<Record<string, unknown>>;
|
|
14
|
+
attributes?: Array<Record<string, unknown>>;
|
|
15
|
+
events?: Array<Record<string, unknown>>;
|
|
16
|
+
keyboard?: Array<Record<string, unknown>>;
|
|
17
|
+
example?: string;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { DomElementBase, createRoving, defineDomElement } from './base.js';
|
|
2
|
+
|
|
3
|
+
function valueOf(option) {
|
|
4
|
+
return option.dataset.value ?? option.textContent.trim();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class DomListboxElement extends DomElementBase {
|
|
8
|
+
static get observedAttributes() { return ['value', 'orientation']; }
|
|
9
|
+
|
|
10
|
+
static __doc = {
|
|
11
|
+
name: 'dom-listbox',
|
|
12
|
+
description: 'A selectable option list with roving focus, selected state, and keyboard navigation.',
|
|
13
|
+
slots: [{ name: '(default)', description: 'Options. Add role="option" and data-value to each selectable item.' }],
|
|
14
|
+
attributes: [
|
|
15
|
+
{ name: 'value', type: 'string', description: 'Selected option value.' },
|
|
16
|
+
{ name: 'orientation', type: "'vertical' | 'horizontal'", description: 'Arrow-key direction. Defaults to vertical.' },
|
|
17
|
+
],
|
|
18
|
+
events: [
|
|
19
|
+
{ name: 'dom:change', payload: '{ value, option }', description: 'Fired when selection changes.' },
|
|
20
|
+
{ name: 'dom:select', payload: '{ value, option }', description: 'Fired when an option is selected.' },
|
|
21
|
+
],
|
|
22
|
+
keyboard: [
|
|
23
|
+
{ keys: '↑ / ↓', action: 'Move active option.' },
|
|
24
|
+
{ keys: 'Home / End', action: 'Jump to first / last option.' },
|
|
25
|
+
{ keys: 'Enter / Space', action: 'Select active option.' },
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
this._roving = null;
|
|
32
|
+
this._observer = null;
|
|
33
|
+
this._refreshFrame = 0;
|
|
34
|
+
this._onKey = this._onKey.bind(this);
|
|
35
|
+
this._onClick = this._onClick.bind(this);
|
|
36
|
+
this._scheduleRefresh = this._scheduleRefresh.bind(this);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
connectedCallback() {
|
|
40
|
+
this.setAttribute('role', this.getAttribute('role') || 'listbox');
|
|
41
|
+
this._refresh();
|
|
42
|
+
this.on(this, 'keydown', this._onKey);
|
|
43
|
+
this.on(this, 'click', this._onClick);
|
|
44
|
+
this._observer = new MutationObserver(this._scheduleRefresh);
|
|
45
|
+
this._observer.observe(this, {
|
|
46
|
+
attributes: true,
|
|
47
|
+
attributeFilter: ['aria-disabled', 'data-value', 'disabled', 'role'],
|
|
48
|
+
childList: true,
|
|
49
|
+
subtree: true,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
attributeChangedCallback() {
|
|
54
|
+
this._refresh();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get value() { return this.getAttribute('value') || ''; }
|
|
58
|
+
set value(value) {
|
|
59
|
+
if (value == null || value === '') this.removeAttribute('value');
|
|
60
|
+
else this.setAttribute('value', value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get options() {
|
|
64
|
+
return Array.from(this.querySelectorAll('[role="option"]'))
|
|
65
|
+
.filter((option) => !option.hasAttribute('disabled') && option.getAttribute('aria-disabled') !== 'true');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_scheduleRefresh() {
|
|
69
|
+
if (this._refreshFrame) return;
|
|
70
|
+
this._refreshFrame = requestAnimationFrame(() => {
|
|
71
|
+
this._refreshFrame = 0;
|
|
72
|
+
this._refresh();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
_refresh() {
|
|
77
|
+
const options = this.options;
|
|
78
|
+
const orientation = this.getAttribute('orientation') || 'vertical';
|
|
79
|
+
const focused = options.findIndex((option) => option === document.activeElement || option.contains(document.activeElement));
|
|
80
|
+
const selected = options.findIndex((option) => valueOf(option) === this.value);
|
|
81
|
+
const active = focused >= 0 ? focused : Math.max(0, selected);
|
|
82
|
+
this.setAttribute('aria-orientation', orientation);
|
|
83
|
+
options.forEach((option, index) => {
|
|
84
|
+
option.tabIndex = index === active ? 0 : -1;
|
|
85
|
+
option.setAttribute('aria-selected', String(valueOf(option) === this.value));
|
|
86
|
+
});
|
|
87
|
+
this._roving = createRoving({ items: options, orientation, loop: true });
|
|
88
|
+
this._roving.setActive(active, { focus: false, select: false });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_select(option, event) {
|
|
92
|
+
const value = valueOf(option);
|
|
93
|
+
const changed = value !== this.value;
|
|
94
|
+
this.value = value;
|
|
95
|
+
this._refresh();
|
|
96
|
+
this.emit('dom:select', { value, option, event });
|
|
97
|
+
if (changed) this.emit('dom:change', { value, option, event });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_onClick(event) {
|
|
101
|
+
const option = event.target.closest('[role="option"]');
|
|
102
|
+
if (!option || !this.contains(option)) return;
|
|
103
|
+
this._select(option, event);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_onKey(event) {
|
|
107
|
+
this._roving?.onKey(event);
|
|
108
|
+
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
109
|
+
const option = document.activeElement?.closest?.('[role="option"]');
|
|
110
|
+
if (!option || !this.contains(option)) return;
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
this._select(option, event);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
disconnectedCallback() {
|
|
116
|
+
this._observer?.disconnect();
|
|
117
|
+
this._observer = null;
|
|
118
|
+
if (this._refreshFrame) {
|
|
119
|
+
cancelAnimationFrame(this._refreshFrame);
|
|
120
|
+
this._refreshFrame = 0;
|
|
121
|
+
}
|
|
122
|
+
super.disconnectedCallback();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
defineDomElement('dom-listbox', DomListboxElement);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// Generated by scripts/generate-types.mjs. Do not edit by hand.
|
|
3
|
+
import { DomElementBase } from './base.js';
|
|
4
|
+
export declare class DomMenuElement extends DomElementBase {
|
|
5
|
+
static readonly observedAttributes?: Array<string>;
|
|
6
|
+
static readonly __doc?: HeadlessElementDoc;
|
|
7
|
+
readonly items: Array<HTMLElement>;
|
|
8
|
+
}
|
|
9
|
+
export interface HeadlessElementDoc {
|
|
10
|
+
name?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
slots?: Array<Record<string, unknown>>;
|
|
13
|
+
attributes?: Array<Record<string, unknown>>;
|
|
14
|
+
events?: Array<Record<string, unknown>>;
|
|
15
|
+
keyboard?: Array<Record<string, unknown>>;
|
|
16
|
+
example?: string;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|