@realmorg/ui 0.0.0-stage → 2.0.0-alpha.2

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 (66) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +44 -2
  3. package/components/accordion.html +121 -0
  4. package/components/alert-dialog.html +196 -0
  5. package/components/alert.html +69 -0
  6. package/components/aspect-ratio.html +23 -0
  7. package/components/attachment.html +84 -0
  8. package/components/avatar.html +127 -0
  9. package/components/badge.html +56 -0
  10. package/components/breadcrumb.html +129 -0
  11. package/components/bubble.html +67 -0
  12. package/components/button-group.html +84 -0
  13. package/components/button.html +188 -0
  14. package/components/calendar.html +170 -0
  15. package/components/card.html +113 -0
  16. package/components/carousel.html +186 -0
  17. package/components/chart.html +162 -0
  18. package/components/checkbox.html +93 -0
  19. package/components/code-block.html +58 -0
  20. package/components/collapsible.html +76 -0
  21. package/components/combobox.html +224 -0
  22. package/components/command.html +189 -0
  23. package/components/context-menu.html +67 -0
  24. package/components/dialog.html +281 -0
  25. package/components/direction.html +17 -0
  26. package/components/drawer.html +224 -0
  27. package/components/dropdown-menu.html +372 -0
  28. package/components/empty.html +106 -0
  29. package/components/field.html +117 -0
  30. package/components/hover-card.html +94 -0
  31. package/components/input-group.html +75 -0
  32. package/components/input-otp.html +139 -0
  33. package/components/input.html +82 -0
  34. package/components/item.html +170 -0
  35. package/components/kbd.html +35 -0
  36. package/components/label.html +40 -0
  37. package/components/marker.html +35 -0
  38. package/components/menubar.html +116 -0
  39. package/components/message-scroller.html +62 -0
  40. package/components/message.html +77 -0
  41. package/components/navigation-menu.html +204 -0
  42. package/components/pagination.html +154 -0
  43. package/components/popover.html +133 -0
  44. package/components/progress.html +39 -0
  45. package/components/radio-group.html +114 -0
  46. package/components/resizable.html +156 -0
  47. package/components/scroll-area.html +50 -0
  48. package/components/select.html +91 -0
  49. package/components/separator.html +25 -0
  50. package/components/sheet.html +143 -0
  51. package/components/sidebar.html +343 -0
  52. package/components/skeleton.html +30 -0
  53. package/components/slider.html +81 -0
  54. package/components/spinner.html +47 -0
  55. package/components/switch.html +89 -0
  56. package/components/table.html +75 -0
  57. package/components/tabs.html +164 -0
  58. package/components/textarea.html +68 -0
  59. package/components/toaster.html +128 -0
  60. package/components/toggle-group.html +65 -0
  61. package/components/toggle.html +81 -0
  62. package/components/tooltip.html +97 -0
  63. package/dist/theme.css +145 -0
  64. package/dist/ui.html +6944 -0
  65. package/package.json +40 -3
  66. package/theme.css +145 -0
@@ -0,0 +1,164 @@
1
+ <custom-element name="ui-tabs">
2
+ <script>
3
+ const props = defineProps({
4
+ value: prop.string(),
5
+ orientation: prop.enum(["horizontal", "vertical"]).default("horizontal"),
6
+ });
7
+
8
+ const parts = useChildren("ui-tabs-list, ui-tabs-content", ["value", "disabled"]);
9
+ const tabs = useState({
10
+ get orientation() {
11
+ return props.orientation;
12
+ },
13
+ get focusgroup() {
14
+ return `tablist ${props.orientation === "vertical" ? "block" : "inline"} wrap`;
15
+ },
16
+ get triggers() {
17
+ return parts.flatMap((part) => [...part.querySelectorAll("ui-tabs-trigger")]);
18
+ },
19
+ get current() {
20
+ const enabled = this.triggers.filter((trigger) => !trigger.hasAttribute("disabled")).map((trigger) => trigger.getAttribute("value"));
21
+ return enabled.includes(props.value) ? props.value : (enabled[0] ?? null);
22
+ },
23
+ });
24
+
25
+ function select(value) {
26
+ if (value === tabs.current) return;
27
+ props.value = value;
28
+ dispatch("change");
29
+ }
30
+
31
+ observe(() => {
32
+ for (const content of parts.filter((part) => part.localName === "ui-tabs-content")) {
33
+ const value = content.getAttribute("value");
34
+ content.hidden = value !== tabs.current;
35
+ content.ariaLabelledByElements = tabs.triggers.filter((trigger) => trigger.getAttribute("value") === value);
36
+ }
37
+ });
38
+ </script>
39
+
40
+ <style>
41
+ :host {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: calc(var(--spacing) * 2);
45
+ }
46
+ :host(:state(attr-orientation-is-vertical)) {
47
+ flex-direction: row;
48
+ --ui-tabs-list-direction: column;
49
+ --ui-tabs-list-height: fit-content;
50
+ }
51
+ </style>
52
+
53
+ <slot></slot>
54
+ </custom-element>
55
+
56
+ <custom-element name="ui-tabs-list">
57
+ <style>
58
+ :host {
59
+ display: block;
60
+ width: fit-content;
61
+ }
62
+ [role="tablist"] {
63
+ display: inline-flex;
64
+ flex-direction: var(--ui-tabs-list-direction, row);
65
+ height: var(--ui-tabs-list-height, calc(var(--spacing) * 9));
66
+ align-items: center;
67
+ justify-content: center;
68
+ padding: 3px;
69
+ box-sizing: border-box;
70
+ border-radius: var(--radius-lg);
71
+ background: var(--muted);
72
+ color: var(--muted-foreground);
73
+ }
74
+ </style>
75
+
76
+ <div role="tablist" part="list" _aria-orientation="#tabs.orientation" _focusgroup="#tabs.focusgroup"><slot></slot></div>
77
+ </custom-element>
78
+
79
+ <custom-element name="ui-tabs-trigger">
80
+ <script>
81
+ const props = defineProps({ value: prop.string(), disabled: prop.boolean() });
82
+ const tabs = lookup("tabs");
83
+ const tab = useState({
84
+ get selected() {
85
+ return props.value === tabs.current;
86
+ },
87
+ get tabindex() {
88
+ return this.selected ? 0 : -1;
89
+ },
90
+ });
91
+ </script>
92
+
93
+ <style>
94
+ :host {
95
+ display: flex;
96
+ flex: 1;
97
+ align-self: stretch;
98
+ }
99
+ button {
100
+ all: unset;
101
+ box-sizing: border-box;
102
+ display: inline-flex;
103
+ flex: 1;
104
+ height: calc(100% - 1px);
105
+ align-items: center;
106
+ justify-content: center;
107
+ gap: calc(var(--spacing) * 1.5);
108
+ padding: calc(var(--spacing) * 1) calc(var(--spacing) * 2);
109
+ border: 1px solid transparent;
110
+ border-radius: var(--radius-md);
111
+ font-size: var(--text-sm);
112
+ font-weight: var(--font-weight-medium);
113
+ white-space: nowrap;
114
+ color: color-mix(in oklab, var(--foreground) 60%, transparent);
115
+ cursor: pointer;
116
+ transition: color var(--default-transition-duration), box-shadow var(--default-transition-duration);
117
+ }
118
+ button:hover {
119
+ color: var(--foreground);
120
+ }
121
+ button[aria-selected="true"] {
122
+ background: var(--background);
123
+ color: var(--foreground);
124
+ box-shadow: var(--shadow-xs);
125
+ }
126
+ button:focus-visible {
127
+ border-color: var(--ring);
128
+ box-shadow: var(--focus-ring);
129
+ }
130
+ button:disabled {
131
+ pointer-events: none;
132
+ opacity: 0.5;
133
+ }
134
+ ::slotted(svg) {
135
+ width: calc(var(--spacing) * 4);
136
+ height: calc(var(--spacing) * 4);
137
+ flex-shrink: 0;
138
+ }
139
+ </style>
140
+
141
+ <button type="button"
142
+ role="tab"
143
+ part="trigger"
144
+ _aria-selected="#tab.selected"
145
+ _tabindex="#tab.tabindex"
146
+ _disabled="@disabled"
147
+ onclick="select(props.value)"
148
+ onfocus="select(props.value)"><slot></slot></button>
149
+ </custom-element>
150
+
151
+ <custom-element name="ui-tabs-content" role="tabpanel">
152
+ <style>
153
+ :host {
154
+ display: block;
155
+ flex: 1;
156
+ outline: none;
157
+ }
158
+ :host([hidden]) {
159
+ display: none;
160
+ }
161
+ </style>
162
+
163
+ <slot></slot>
164
+ </custom-element>
@@ -0,0 +1,68 @@
1
+ <custom-element name="ui-textarea" form-associated delegates-focus>
2
+ <script>
3
+ defineProps({
4
+ value: prop.string().default(""),
5
+ placeholder: prop.string(),
6
+ rows: prop.number().int().min(1).default(3),
7
+ minlength: prop.number(),
8
+ maxlength: prop.number(),
9
+ disabled: prop.boolean(),
10
+ readonly: prop.boolean(),
11
+ required: prop.boolean(),
12
+ invalid: prop.boolean(),
13
+ label: prop.string().attribute("aria-label"),
14
+ });
15
+ </script>
16
+
17
+ <style>
18
+ :host {
19
+ display: block;
20
+ }
21
+ textarea {
22
+ box-sizing: border-box;
23
+ display: block;
24
+ width: 100%;
25
+ min-height: calc(var(--spacing) * 16);
26
+ padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
27
+ border: 1px solid var(--input);
28
+ border-radius: var(--radius-md);
29
+ background: transparent;
30
+ color: inherit;
31
+ font: inherit;
32
+ font-size: var(--text-sm);
33
+ box-shadow: var(--shadow-xs);
34
+ outline: none;
35
+ field-sizing: content;
36
+ resize: vertical;
37
+ }
38
+ textarea::placeholder {
39
+ color: var(--muted-foreground);
40
+ }
41
+ textarea:focus-visible {
42
+ border-color: var(--ring);
43
+ box-shadow: var(--focus-ring);
44
+ }
45
+ textarea:disabled {
46
+ cursor: not-allowed;
47
+ opacity: 0.5;
48
+ }
49
+ textarea[aria-invalid="true"] {
50
+ border-color: var(--destructive);
51
+ }
52
+ </style>
53
+
54
+ <textarea
55
+ ref="control"
56
+ _aria-label="@label"
57
+ part="textarea"
58
+ _value="@value"
59
+ _placeholder="@placeholder"
60
+ _rows="@rows"
61
+ _minlength="@minlength"
62
+ _maxlength="@maxlength"
63
+ _disabled="@disabled"
64
+ _readonly="@readonly"
65
+ _required="@required"
66
+ _aria-invalid="@invalid"
67
+ ></textarea>
68
+ </custom-element>
@@ -0,0 +1,128 @@
1
+ <custom-element name="ui-toaster">
2
+ <script>
3
+ const props = defineProps({
4
+ position: prop.enum(["bottom-right", "bottom-left", "bottom-center", "top-right", "top-left", "top-center"]).default("bottom-right"),
5
+ duration: prop.number().min(0).default(4000),
6
+ });
7
+
8
+ const toasts = useState({ list: [] });
9
+ const timers = new Map();
10
+ let counter = 0;
11
+
12
+ function dismiss(toast) {
13
+ clearTimeout(timers.get(toast.id));
14
+ timers.delete(toast.id);
15
+ const index = toasts.list.findIndex((item) => item.id === toast.id);
16
+ if (index !== -1) toasts.list.splice(index, 1);
17
+ }
18
+
19
+ function add(detail = {}) {
20
+ const toast = {
21
+ id: ++counter,
22
+ title: detail.title ?? "",
23
+ description: detail.description ?? "",
24
+ variant: detail.variant ?? "default",
25
+ };
26
+ toasts.list.push(toast);
27
+ const duration = detail.duration ?? props.duration;
28
+ if (duration > 0) timers.set(toast.id, setTimeout(() => dismiss(toast), duration));
29
+ return toast.id;
30
+ }
31
+
32
+ defineMethods({ toast: add, dismiss: (id) => dismiss({ id }) });
33
+ listen("toast", (event) => add(event.detail), document);
34
+ onConnected(() => {
35
+ observe(() => {
36
+ const region = refs.region;
37
+ const open = toasts.list.length > 0;
38
+ if (!region.isConnected) return;
39
+ if (open && !region.matches(":popover-open")) region.showPopover();
40
+ if (!open && region.matches(":popover-open")) region.hidePopover();
41
+ });
42
+ });
43
+ </script>
44
+
45
+ <style>
46
+ ol {
47
+ position: fixed;
48
+ inset: auto calc(var(--spacing) * 4) calc(var(--spacing) * 4) auto;
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: calc(var(--spacing) * 2);
52
+ width: min(calc(var(--spacing) * 88), calc(100% - calc(var(--spacing) * 8)));
53
+ margin: 0;
54
+ padding: 0;
55
+ border: 0;
56
+ background: transparent;
57
+ list-style: none;
58
+ overflow: visible;
59
+ }
60
+ :host(:state(attr-position-is-bottom-left)) ol {
61
+ inset: auto auto calc(var(--spacing) * 4) calc(var(--spacing) * 4);
62
+ }
63
+ :host(:state(attr-position-is-bottom-center)) ol {
64
+ inset: auto 0 calc(var(--spacing) * 4) 0;
65
+ margin: 0 auto;
66
+ }
67
+ :host(:state(attr-position-is-top-right)) ol {
68
+ inset: calc(var(--spacing) * 4) calc(var(--spacing) * 4) auto auto;
69
+ }
70
+ :host(:state(attr-position-is-top-left)) ol {
71
+ inset: calc(var(--spacing) * 4) auto auto calc(var(--spacing) * 4);
72
+ }
73
+ :host(:state(attr-position-is-top-center)) ol {
74
+ inset: calc(var(--spacing) * 4) 0 auto 0;
75
+ margin: 0 auto;
76
+ }
77
+ li {
78
+ position: relative;
79
+ display: grid;
80
+ gap: calc(var(--spacing) * 1);
81
+ padding: calc(var(--spacing) * 4) calc(var(--spacing) * 10) calc(var(--spacing) * 4) calc(var(--spacing) * 4);
82
+ border: 1px solid var(--border);
83
+ border-radius: var(--radius-lg);
84
+ background: var(--popover);
85
+ color: var(--popover-foreground);
86
+ font-size: var(--text-sm);
87
+ box-shadow: var(--shadow-md);
88
+ animation: enter 0.2s ease-out;
89
+ }
90
+ li[data-variant="destructive"] {
91
+ border-color: var(--destructive);
92
+ color: var(--destructive);
93
+ }
94
+ strong {
95
+ font-weight: var(--font-weight-semibold);
96
+ }
97
+ p {
98
+ margin: 0;
99
+ color: var(--muted-foreground);
100
+ }
101
+ button {
102
+ all: unset;
103
+ position: absolute;
104
+ top: calc(var(--spacing) * 3);
105
+ right: calc(var(--spacing) * 3);
106
+ cursor: pointer;
107
+ opacity: 0.6;
108
+ }
109
+ button:hover,
110
+ button:focus-visible {
111
+ opacity: 1;
112
+ }
113
+ @keyframes enter {
114
+ from {
115
+ opacity: 0;
116
+ translate: 0 calc(var(--spacing) * 2);
117
+ }
118
+ }
119
+ </style>
120
+
121
+ <ol ref="region" part="region" popover="manual" aria-live="polite">
122
+ <li repeat="#toasts.list" as="toast" key="id" part="toast" _data-variant="#toast.variant">
123
+ <strong><slot name="#toast.title"></slot></strong>
124
+ <p _hidden="!#toast.description"><slot name="#toast.description"></slot></p>
125
+ <button type="button" aria-label="Dismiss" onclick="dismiss(toast)">×</button>
126
+ </li>
127
+ </ol>
128
+ </custom-element>
@@ -0,0 +1,65 @@
1
+ <import-element from="./toggle.html"></import-element>
2
+
3
+ <custom-element name="ui-toggle-group" role="group" form-associated>
4
+ <script>
5
+ const props = defineProps({
6
+ type: prop.enum(["single", "multiple"]).default("single"),
7
+ value: prop.string().default(""),
8
+ orientation: prop.enum(["horizontal", "vertical"]).default("horizontal"),
9
+ });
10
+
11
+ const toggles = useChildren("ui-toggle");
12
+ const group = useState({
13
+ get focusgroup() {
14
+ return `toolbar ${props.orientation === "vertical" ? "block" : "inline"} wrap`;
15
+ },
16
+ get selected() {
17
+ return new Set(props.value.split(",").filter(Boolean));
18
+ },
19
+ });
20
+
21
+ function changed(event) {
22
+ const toggle = event.target;
23
+ if (toggle.localName !== "ui-toggle") return;
24
+ event.stopPropagation();
25
+ const value = toggle.value;
26
+ const selected = props.type === "single" ? new Set(toggle.pressed ? [value] : []) : new Set(group.selected);
27
+ if (props.type === "multiple") selected[toggle.pressed ? "add" : "delete"](value);
28
+ props.value = [...selected].join(",");
29
+ dispatch("change");
30
+ }
31
+
32
+ listen("change", changed);
33
+
34
+ observe(() => {
35
+ for (const toggle of toggles) toggle.pressed = group.selected.has(toggle.value);
36
+ });
37
+ </script>
38
+
39
+ <style>
40
+ :host {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ width: fit-content;
44
+ border-radius: var(--radius-md);
45
+ }
46
+ :host(:state(attr-orientation-is-vertical)) {
47
+ flex-direction: column;
48
+ align-items: stretch;
49
+ }
50
+ :host(:not(:state(attr-orientation-is-vertical))) ::slotted(:not(:first-child)) {
51
+ --ui-radius-start: 0;
52
+ }
53
+ :host(:not(:state(attr-orientation-is-vertical))) ::slotted(:not(:last-child)) {
54
+ --ui-radius-end: 0;
55
+ }
56
+ :host(:state(attr-orientation-is-vertical)) ::slotted(:not(:first-child)) {
57
+ --ui-radius-block-start: 0;
58
+ }
59
+ :host(:state(attr-orientation-is-vertical)) ::slotted(:not(:last-child)) {
60
+ --ui-radius-block-end: 0;
61
+ }
62
+ </style>
63
+
64
+ <div part="group" _focusgroup="#group.focusgroup" style="display: contents"><slot></slot></div>
65
+ </custom-element>
@@ -0,0 +1,81 @@
1
+ <custom-element name="ui-toggle" delegates-focus>
2
+ <script>
3
+ const props = defineProps({
4
+ pressed: prop.boolean().reflect(),
5
+ variant: prop.enum(["default", "outline"]).default("default"),
6
+ size: prop.enum(["default", "sm", "lg"]).default("default"),
7
+ disabled: prop.boolean(),
8
+ value: prop.string(),
9
+ label: prop.string().attribute("aria-label"),
10
+ });
11
+
12
+ function toggle() {
13
+ props.pressed = !props.pressed;
14
+ dispatch("change");
15
+ }
16
+ </script>
17
+
18
+ <style>
19
+ :host {
20
+ display: inline-flex;
21
+ }
22
+ button {
23
+ all: unset;
24
+ box-sizing: border-box;
25
+ display: inline-flex;
26
+ flex: 1;
27
+ align-items: center;
28
+ justify-content: center;
29
+ gap: calc(var(--spacing) * 2);
30
+ min-width: calc(var(--spacing) * 9);
31
+ height: calc(var(--spacing) * 9);
32
+ padding: 0 calc(var(--spacing) * 2);
33
+ border: 1px solid transparent;
34
+ border-radius: var(--radius-md);
35
+ border-start-start-radius: var(--ui-radius-block-start, var(--ui-radius-start, var(--radius-md)));
36
+ border-end-start-radius: var(--ui-radius-block-end, var(--ui-radius-start, var(--radius-md)));
37
+ border-start-end-radius: var(--ui-radius-block-start, var(--ui-radius-end, var(--radius-md)));
38
+ border-end-end-radius: var(--ui-radius-block-end, var(--ui-radius-end, var(--radius-md)));
39
+ font-size: var(--text-sm);
40
+ font-weight: var(--font-weight-medium);
41
+ cursor: pointer;
42
+ transition: background-color var(--default-transition-duration), color var(--default-transition-duration);
43
+ }
44
+ button:hover {
45
+ background: var(--muted);
46
+ color: var(--muted-foreground);
47
+ }
48
+ :host(:state(attr-pressed)) button {
49
+ background: var(--accent);
50
+ color: var(--accent-foreground);
51
+ }
52
+ :host(:state(attr-variant-is-outline)) button {
53
+ border-color: var(--input);
54
+ box-shadow: var(--shadow-xs);
55
+ }
56
+ :host(:state(attr-size-is-sm)) button {
57
+ min-width: calc(var(--spacing) * 8);
58
+ height: calc(var(--spacing) * 8);
59
+ padding: 0 calc(var(--spacing) * 1.5);
60
+ }
61
+ :host(:state(attr-size-is-lg)) button {
62
+ min-width: calc(var(--spacing) * 10);
63
+ height: calc(var(--spacing) * 10);
64
+ padding: 0 calc(var(--spacing) * 2.5);
65
+ }
66
+ button:focus-visible {
67
+ border-color: var(--ring);
68
+ box-shadow: var(--focus-ring);
69
+ }
70
+ button:disabled {
71
+ pointer-events: none;
72
+ opacity: 0.5;
73
+ }
74
+ ::slotted(svg) {
75
+ width: calc(var(--spacing) * 4);
76
+ height: calc(var(--spacing) * 4);
77
+ }
78
+ </style>
79
+
80
+ <button type="button" part="button" _aria-pressed="@pressed" _aria-label="@label" _disabled="@disabled" onclick="toggle()"><slot></slot></button>
81
+ </custom-element>
@@ -0,0 +1,97 @@
1
+ <custom-element name="ui-tooltip">
2
+ <script>
3
+ const props = defineProps({
4
+ delay: prop.number().min(0).default(300),
5
+ });
6
+
7
+ const parts = useChildren("ui-tooltip-trigger, ui-tooltip-content");
8
+
9
+ let timer;
10
+
11
+ function tip() {
12
+ return parts.find((part) => part.localName === "ui-tooltip-content");
13
+ }
14
+
15
+ function show(trigger) {
16
+ clearTimeout(timer);
17
+ timer = setTimeout(() => {
18
+ if (!tip().matches(":popover-open")) tip().showPopover({ source: trigger });
19
+ }, props.delay);
20
+ }
21
+
22
+ function hide() {
23
+ clearTimeout(timer);
24
+ if (tip().matches(":popover-open")) tip().hidePopover();
25
+ }
26
+
27
+ function key(event) {
28
+ if (event.key === "Escape") hide();
29
+ }
30
+
31
+ function describe() {
32
+ const text = tip()?.textContent.trim() ?? "";
33
+ for (const trigger of parts.filter((part) => part.localName === "ui-tooltip-trigger"))
34
+ for (const element of trigger.children) element.setAttribute("aria-description", text);
35
+ }
36
+
37
+ observe(describe);
38
+ </script>
39
+
40
+ <style>
41
+ :host {
42
+ display: contents;
43
+ }
44
+ </style>
45
+
46
+ <slot></slot>
47
+ </custom-element>
48
+
49
+ <custom-element name="ui-tooltip-trigger">
50
+ <style>
51
+ :host {
52
+ display: inline-block;
53
+ vertical-align: middle;
54
+ }
55
+ </style>
56
+
57
+ <span part="trigger" onpointerenter="show(host)" onpointerleave="hide()" onfocusin="show(host)" onfocusout="hide()" onkeydown="key(event)"><slot></slot></span>
58
+ </custom-element>
59
+
60
+ <custom-element name="ui-tooltip-content" role="tooltip">
61
+ <script>
62
+ defineProps({
63
+ placement: prop.enum(["top", "bottom", "left", "right"]).default("top"),
64
+ });
65
+
66
+ attrs.popover ??= "manual";
67
+ </script>
68
+
69
+ <style>
70
+ :host {
71
+ margin: 0 0 calc(var(--spacing) * 1);
72
+ padding: calc(var(--spacing) * 1.5) calc(var(--spacing) * 3);
73
+ border: 0;
74
+ border-radius: var(--radius-md);
75
+ background: var(--foreground);
76
+ color: var(--background);
77
+ font-size: var(--text-xs);
78
+ inset: auto;
79
+ position-area: top;
80
+ position-try-fallbacks: flip-block;
81
+ }
82
+ :host(:state(attr-placement-is-bottom)) {
83
+ position-area: bottom;
84
+ margin: calc(var(--spacing) * 1) 0 0;
85
+ }
86
+ :host(:state(attr-placement-is-left)) {
87
+ position-area: left;
88
+ margin: 0 calc(var(--spacing) * 1) 0 0;
89
+ }
90
+ :host(:state(attr-placement-is-right)) {
91
+ position-area: right;
92
+ margin: 0 0 0 calc(var(--spacing) * 1);
93
+ }
94
+ </style>
95
+
96
+ <slot></slot>
97
+ </custom-element>