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

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 +139 -0
  4. package/components/alert-dialog.html +236 -0
  5. package/components/alert.html +83 -0
  6. package/components/aspect-ratio.html +29 -0
  7. package/components/attachment.html +98 -0
  8. package/components/avatar.html +149 -0
  9. package/components/badge.html +62 -0
  10. package/components/breadcrumb.html +159 -0
  11. package/components/bubble.html +77 -0
  12. package/components/button-group.html +98 -0
  13. package/components/button.html +194 -0
  14. package/components/calendar.html +176 -0
  15. package/components/card.html +143 -0
  16. package/components/carousel.html +208 -0
  17. package/components/chart.html +168 -0
  18. package/components/checkbox.html +99 -0
  19. package/components/code-block.html +64 -0
  20. package/components/collapsible.html +90 -0
  21. package/components/combobox.html +237 -0
  22. package/components/command.html +201 -0
  23. package/components/context-menu.html +81 -0
  24. package/components/dialog.html +327 -0
  25. package/components/direction.html +23 -0
  26. package/components/drawer.html +267 -0
  27. package/components/dropdown-menu.html +421 -0
  28. package/components/empty.html +132 -0
  29. package/components/field.html +143 -0
  30. package/components/hover-card.html +111 -0
  31. package/components/input-group.html +91 -0
  32. package/components/input-otp.html +151 -0
  33. package/components/input.html +94 -0
  34. package/components/item.html +208 -0
  35. package/components/kbd.html +45 -0
  36. package/components/label.html +46 -0
  37. package/components/marker.html +41 -0
  38. package/components/menubar.html +137 -0
  39. package/components/message-scroller.html +68 -0
  40. package/components/message.html +95 -0
  41. package/components/navigation-menu.html +233 -0
  42. package/components/pagination.html +160 -0
  43. package/components/popover.html +164 -0
  44. package/components/progress.html +45 -0
  45. package/components/radio-group.html +120 -0
  46. package/components/resizable.html +170 -0
  47. package/components/scroll-area.html +56 -0
  48. package/components/select.html +103 -0
  49. package/components/separator.html +31 -0
  50. package/components/sheet.html +173 -0
  51. package/components/sidebar.html +393 -0
  52. package/components/skeleton.html +36 -0
  53. package/components/slider.html +108 -0
  54. package/components/spinner.html +53 -0
  55. package/components/switch.html +95 -0
  56. package/components/table.html +81 -0
  57. package/components/tabs.html +182 -0
  58. package/components/textarea.html +80 -0
  59. package/components/toaster.html +134 -0
  60. package/components/toggle-group.html +71 -0
  61. package/components/toggle.html +87 -0
  62. package/components/tooltip.html +114 -0
  63. package/dist/theme.css +158 -0
  64. package/dist/ui.html +7923 -0
  65. package/package.json +40 -3
  66. package/theme.css +158 -0
@@ -0,0 +1,208 @@
1
+ <import-element from="./button.html"></import-element>
2
+
3
+ <custom-element name="ui-carousel" role="region">
4
+ <script>
5
+ const props = defineProps({
6
+ orientation: prop.enum(["horizontal", "vertical"]).default("horizontal"),
7
+ label: prop.string().default("Carousel"),
8
+ });
9
+
10
+ const content = useChildren("ui-carousel-content");
11
+ const position = useState({
12
+ index: 0,
13
+ get first() {
14
+ return this.index <= 0;
15
+ },
16
+ get last() {
17
+ return this.index >= slides().length - 1;
18
+ },
19
+ });
20
+ const KEYS = { ArrowLeft: -1, ArrowUp: -1, ArrowRight: 1, ArrowDown: 1 };
21
+
22
+ function slides() {
23
+ return [...(content[0]?.children ?? [])];
24
+ }
25
+
26
+ function settle(index) {
27
+ if (index === position.index) return;
28
+ position.index = index;
29
+ dispatch("change", { index });
30
+ }
31
+
32
+ function go(index) {
33
+ const all = slides();
34
+ const target = Math.max(0, Math.min(index, all.length - 1));
35
+ all[target]?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "start" });
36
+ settle(target);
37
+ }
38
+
39
+ function previous() {
40
+ go(position.index - 1);
41
+ }
42
+
43
+ function next() {
44
+ go(position.index + 1);
45
+ }
46
+
47
+ function keys(event) {
48
+ const step = KEYS[event.key];
49
+ if (!step) return;
50
+ event.preventDefault();
51
+ go(position.index + step);
52
+ }
53
+
54
+ function scrolled(track) {
55
+ const edge = props.orientation === "vertical" ? "top" : "left";
56
+ const start = track.getBoundingClientRect()[edge];
57
+ const distances = slides().map((slide) => Math.abs(slide.getBoundingClientRect()[edge] - start));
58
+ settle(distances.indexOf(Math.min(...distances)));
59
+ }
60
+
61
+ observe(() => {
62
+ internals.ariaLabel = props.label;
63
+ internals.ariaRoleDescription = "carousel";
64
+ });
65
+ </script>
66
+
67
+ <style>
68
+ /* A double tap must not zoom the page. Set inside the shadow root, because a page-level
69
+ touch-action does not reach shadow content in iOS Safari. */
70
+ :host,
71
+ * {
72
+ touch-action: manipulation;
73
+ }
74
+ :host {
75
+ --carousel-direction: row;
76
+ --carousel-axis: x;
77
+ --carousel-overflow-x: auto;
78
+ --carousel-overflow-y: hidden;
79
+ display: grid;
80
+ grid-template-columns: auto minmax(0, 1fr) auto;
81
+ align-items: center;
82
+ width: 100%;
83
+ }
84
+ :host(:state(attr-orientation-is-vertical)) {
85
+ --carousel-direction: column;
86
+ --carousel-axis: y;
87
+ --carousel-overflow-x: hidden;
88
+ --carousel-overflow-y: auto;
89
+ grid-template-columns: minmax(0, 1fr);
90
+ grid-template-rows: auto minmax(0, 1fr) auto;
91
+ justify-items: center;
92
+ }
93
+ :host(:state(attr-height)) {
94
+ height: calc(var(--spacing) * var(--attr-height));
95
+ }
96
+ ::slotted(ui-carousel-content) {
97
+ grid-area: 1 / 2;
98
+ align-self: stretch;
99
+ }
100
+ :host(:state(attr-orientation-is-vertical)) ::slotted(ui-carousel-content) {
101
+ grid-area: 2 / 1;
102
+ justify-self: stretch;
103
+ }
104
+ ::slotted(ui-carousel-previous) {
105
+ grid-area: 1 / 1;
106
+ margin-inline-end: calc(var(--spacing) * 2);
107
+ }
108
+ ::slotted(ui-carousel-next) {
109
+ grid-area: 1 / 3;
110
+ margin-inline-start: calc(var(--spacing) * 2);
111
+ }
112
+ :host(:state(attr-orientation-is-vertical)) ::slotted(ui-carousel-previous) {
113
+ grid-area: 1 / 1;
114
+ margin: 0 0 calc(var(--spacing) * 2);
115
+ rotate: 90deg;
116
+ }
117
+ :host(:state(attr-orientation-is-vertical)) ::slotted(ui-carousel-next) {
118
+ grid-area: 3 / 1;
119
+ margin: calc(var(--spacing) * 2) 0 0;
120
+ rotate: 90deg;
121
+ }
122
+ </style>
123
+
124
+ <slot></slot>
125
+ </custom-element>
126
+
127
+ <custom-element name="ui-carousel-content">
128
+ <style>
129
+ :host,
130
+ * {
131
+ touch-action: manipulation;
132
+ }
133
+ :host {
134
+ display: flex;
135
+ min-width: 0;
136
+ min-height: 0;
137
+ }
138
+ .track {
139
+ display: flex;
140
+ flex: 1;
141
+ flex-direction: var(--carousel-direction);
142
+ gap: calc(var(--spacing) * 4);
143
+ min-width: 0;
144
+ min-height: 0;
145
+ overflow-x: var(--carousel-overflow-x);
146
+ overflow-y: var(--carousel-overflow-y);
147
+ scroll-snap-type: var(--carousel-axis) mandatory;
148
+ scrollbar-width: none;
149
+ outline: none;
150
+ }
151
+ .track:focus-visible {
152
+ box-shadow: var(--focus-ring);
153
+ }
154
+ </style>
155
+
156
+ <div class="track" part="track" tabindex="0" onkeydown="keys(event)" onscrollend="scrolled(this)"><slot></slot></div>
157
+ </custom-element>
158
+
159
+ <custom-element name="ui-carousel-item" role="group">
160
+ <script>
161
+ internals.ariaRoleDescription = "slide";
162
+ </script>
163
+
164
+ <style>
165
+ :host,
166
+ * {
167
+ touch-action: manipulation;
168
+ }
169
+ :host {
170
+ display: block;
171
+ box-sizing: border-box;
172
+ flex: 0 0 100%;
173
+ min-width: 0;
174
+ min-height: 0;
175
+ scroll-snap-align: start;
176
+ }
177
+ </style>
178
+
179
+ <slot></slot>
180
+ </custom-element>
181
+
182
+ <custom-element name="ui-carousel-previous">
183
+ <style>
184
+ :host,
185
+ * {
186
+ touch-action: manipulation;
187
+ }
188
+ :host {
189
+ display: inline-flex;
190
+ }
191
+ </style>
192
+
193
+ <ui-button variant="outline" size="icon" aria-label="Previous slide" _disabled="#position.first" onclick="previous()">‹</ui-button>
194
+ </custom-element>
195
+
196
+ <custom-element name="ui-carousel-next">
197
+ <style>
198
+ :host,
199
+ * {
200
+ touch-action: manipulation;
201
+ }
202
+ :host {
203
+ display: inline-flex;
204
+ }
205
+ </style>
206
+
207
+ <ui-button variant="outline" size="icon" aria-label="Next slide" _disabled="#position.last" onclick="next()">›</ui-button>
208
+ </custom-element>
@@ -0,0 +1,168 @@
1
+ <custom-element name="ui-chart">
2
+ <script>
3
+ const props = defineProps({
4
+ type: prop.enum(["bar", "line", "area"]).default("bar"),
5
+ data: prop.array(prop.object()).default([]),
6
+ x: prop.string().default("label"),
7
+ y: prop.string().default("value"),
8
+ height: prop.number().min(80).default(240),
9
+ label: prop.string().default("Chart"),
10
+ });
11
+
12
+ const WIDTH = 600;
13
+ const PAD = { top: 12, right: 12, bottom: 28, left: 44 };
14
+
15
+ const chart = useState({
16
+ get series() {
17
+ return props.y.split(",").map((key, index) => ({ key: key.trim(), color: `var(--chart-${(index % 5) + 1})` }));
18
+ },
19
+ get values() {
20
+ return props.data.flatMap((row) => this.series.map((series) => Number(row[series.key]) || 0));
21
+ },
22
+ get max() {
23
+ return Math.max(1, ...this.values);
24
+ },
25
+ get min() {
26
+ return Math.min(0, ...this.values);
27
+ },
28
+ get plotHeight() {
29
+ return props.height - PAD.top - PAD.bottom;
30
+ },
31
+ y(value) {
32
+ return PAD.top + this.plotHeight * ((this.max - value) / (this.max - this.min));
33
+ },
34
+ get step() {
35
+ return (WIDTH - PAD.left - PAD.right) / Math.max(1, props.data.length);
36
+ },
37
+ get viewBox() {
38
+ return `0 0 ${WIDTH} ${props.height}`;
39
+ },
40
+ get ticks() {
41
+ return [0, 0.25, 0.5, 0.75, 1].map((ratio) => ({
42
+ key: ratio,
43
+ y: PAD.top + this.plotHeight * (1 - ratio),
44
+ label: Math.round(this.min + (this.max - this.min) * ratio).toLocaleString(),
45
+ }));
46
+ },
47
+ get labels() {
48
+ return props.data.map((row, index) => ({ key: index, x: PAD.left + this.step * (index + 0.5), text: String(row[props.x] ?? "") }));
49
+ },
50
+ get bars() {
51
+ const width = (this.step * 0.7) / this.series.length;
52
+ return props.data.flatMap((row, index) =>
53
+ this.series.map((series, s) => {
54
+ const value = Number(row[series.key]) || 0;
55
+ const top = this.y(Math.max(value, 0));
56
+ return {
57
+ key: `${index}-${series.key}`,
58
+ x: PAD.left + this.step * index + this.step * 0.15 + width * s,
59
+ y: top,
60
+ width,
61
+ height: this.y(Math.min(value, 0)) - top,
62
+ color: series.color,
63
+ title: `${row[props.x]} · ${series.key}: ${value.toLocaleString()}`,
64
+ };
65
+ }),
66
+ );
67
+ },
68
+ get lines() {
69
+ return this.series.map((series) => {
70
+ const points = props.data.map((row, index) => [
71
+ PAD.left + this.step * (index + 0.5),
72
+ this.y(Number(row[series.key]) || 0),
73
+ ]);
74
+ const line = points.map(([x, y], index) => `${index ? "L" : "M"}${x},${y}`).join(" ");
75
+ const zero = this.y(0);
76
+ const area = points.length ? `${line} L${points.at(-1)[0]},${zero} L${points[0][0]},${zero} Z` : "";
77
+ return { key: series.key, line, area, color: series.color };
78
+ });
79
+ },
80
+ get legend() {
81
+ return this.series.length > 1 ? this.series : [];
82
+ },
83
+ });
84
+ </script>
85
+
86
+ <style>
87
+ /* A double tap must not zoom the page. Set inside the shadow root, because a page-level
88
+ touch-action does not reach shadow content in iOS Safari. */
89
+ :host,
90
+ * {
91
+ touch-action: manipulation;
92
+ }
93
+ :host {
94
+ display: block;
95
+ width: 100%;
96
+ box-sizing: border-box;
97
+ font-size: var(--text-xs);
98
+ color: var(--muted-foreground);
99
+ }
100
+ svg {
101
+ display: block;
102
+ width: 100%;
103
+ height: auto;
104
+ overflow: visible;
105
+ }
106
+ .grid {
107
+ stroke: var(--border);
108
+ stroke-dasharray: 3 3;
109
+ }
110
+ .tick {
111
+ fill: currentColor;
112
+ text-anchor: end;
113
+ dominant-baseline: middle;
114
+ }
115
+ .label {
116
+ fill: currentColor;
117
+ text-anchor: middle;
118
+ }
119
+ rect {
120
+ rx: 4;
121
+ }
122
+ .line {
123
+ fill: none;
124
+ stroke-width: 2;
125
+ }
126
+ .area {
127
+ opacity: 0.2;
128
+ }
129
+ :host(:not(:state(attr-type-is-bar))) .bars,
130
+ :host(:state(attr-type-is-bar)) .lines,
131
+ :host(:not(:state(attr-type-is-area))) .area {
132
+ display: none;
133
+ }
134
+ .legend {
135
+ display: flex;
136
+ justify-content: center;
137
+ gap: calc(var(--spacing) * 4);
138
+ margin-top: calc(var(--spacing) * 2);
139
+ }
140
+ .legend span::before {
141
+ content: "";
142
+ display: inline-block;
143
+ width: calc(var(--spacing) * 2.5);
144
+ height: calc(var(--spacing) * 2.5);
145
+ margin-right: calc(var(--spacing) * 1.5);
146
+ border-radius: var(--radius-xs);
147
+ background: var(--swatch);
148
+ }
149
+ </style>
150
+
151
+ <svg _viewBox="#chart.viewBox" role="img" _aria-label="@label" part="svg">
152
+ <g repeat="#chart.ticks" as="tick" key="key">
153
+ <line class="grid" x1="44" x2="588" _y1="#tick.y" _y2="#tick.y"></line>
154
+ <text class="tick" x="38" _y="#tick.y"><slot name="#tick.label"></slot></text>
155
+ </g>
156
+ <text repeat="#chart.labels" as="label" key="key" class="label" _x="#label.x" _y="@height" dy="-8"><slot name="#label.text"></slot></text>
157
+ <g class="bars">
158
+ <rect repeat="#chart.bars" as="bar" key="key" _x="#bar.x" _y="#bar.y" _width="#bar.width" _height="#bar.height" _fill="#bar.color"><title><slot name="#bar.title"></slot></title></rect>
159
+ </g>
160
+ <g class="lines" repeat="#chart.lines" as="series" key="key">
161
+ <path class="area" _d="#series.area" _fill="#series.color"></path>
162
+ <path class="line" _d="#series.line" _stroke="#series.color"></path>
163
+ </g>
164
+ </svg>
165
+ <div class="legend" part="legend">
166
+ <span repeat="#chart.legend" as="series" key="key" _--swatch="#series.color"><slot name="#series.key"></slot></span>
167
+ </div>
168
+ </custom-element>
@@ -0,0 +1,99 @@
1
+ <custom-element name="ui-checkbox" form-associated delegates-focus>
2
+ <script>
3
+ const props = defineProps({
4
+ checked: prop.boolean(),
5
+ value: prop.string(),
6
+ indeterminate: prop.boolean(),
7
+ disabled: prop.boolean(),
8
+ required: prop.boolean(),
9
+ label: prop.string().attribute("aria-label"),
10
+ });
11
+
12
+ function settled() {
13
+ props.indeterminate = false;
14
+ }
15
+ </script>
16
+
17
+ <style>
18
+ /* A double tap must not zoom the page. Set inside the shadow root, because a page-level
19
+ touch-action does not reach shadow content in iOS Safari. */
20
+ :host,
21
+ * {
22
+ touch-action: manipulation;
23
+ }
24
+ :host(:state(attr-checked)) label {
25
+ color: var(--foreground);
26
+ }
27
+ :host {
28
+ display: inline-flex;
29
+ align-items: center;
30
+ gap: calc(var(--spacing) * 2);
31
+ vertical-align: middle;
32
+ }
33
+ input {
34
+ appearance: none;
35
+ box-sizing: border-box;
36
+ display: grid;
37
+ place-content: center;
38
+ width: calc(var(--spacing) * 4);
39
+ height: calc(var(--spacing) * 4);
40
+ margin: 0;
41
+ border: 1px solid var(--input);
42
+ border-radius: var(--radius-xs);
43
+ background: transparent;
44
+ box-shadow: var(--shadow-xs);
45
+ cursor: pointer;
46
+ outline: none;
47
+ transition: box-shadow var(--default-transition-duration);
48
+ }
49
+ input::before {
50
+ content: "";
51
+ width: calc(var(--spacing) * 2.5);
52
+ height: calc(var(--spacing) * 2.5);
53
+ background: currentColor;
54
+ clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
55
+ transform: scale(0);
56
+ transition: transform 0.1s;
57
+ }
58
+ input:checked,
59
+ input:indeterminate {
60
+ background: var(--primary);
61
+ border-color: var(--primary);
62
+ color: var(--primary-foreground);
63
+ }
64
+ input:checked::before {
65
+ transform: scale(1);
66
+ }
67
+ input:indeterminate::before {
68
+ clip-path: inset(40% 0);
69
+ transform: scale(1);
70
+ }
71
+ input:focus-visible {
72
+ border-color: var(--ring);
73
+ box-shadow: var(--focus-ring);
74
+ }
75
+ input:disabled {
76
+ cursor: not-allowed;
77
+ opacity: 0.5;
78
+ }
79
+ label {
80
+ font-size: var(--text-sm);
81
+ font-weight: var(--font-weight-medium);
82
+ line-height: 1;
83
+ }
84
+ </style>
85
+
86
+ <input
87
+ id="control"
88
+ ref="control"
89
+ part="control"
90
+ type="checkbox"
91
+ _aria-label="@label"
92
+ _checked="@checked"
93
+ _indeterminate="@indeterminate"
94
+ _disabled="@disabled"
95
+ _required="@required"
96
+ onchange="settled()"
97
+ >
98
+ <label for="control" part="label"><slot></slot></label>
99
+ </custom-element>
@@ -0,0 +1,64 @@
1
+ <import-element from="./button.html"></import-element>
2
+
3
+ <custom-element name="ui-code-block">
4
+ <script>
5
+ defineProps({ language: prop.string() });
6
+
7
+ const copy = useState({ done: false });
8
+
9
+ async function copyCode() {
10
+ await navigator.clipboard.writeText(host.textContent.trim());
11
+ copy.done = true;
12
+ setTimeout(() => (copy.done = false), 1500);
13
+ }
14
+ </script>
15
+
16
+ <style>
17
+ /* A double tap must not zoom the page. Set inside the shadow root, because a page-level
18
+ touch-action does not reach shadow content in iOS Safari. */
19
+ :host,
20
+ * {
21
+ touch-action: manipulation;
22
+ }
23
+ :host {
24
+ position: relative;
25
+ display: block;
26
+ width: 100%;
27
+ box-sizing: border-box;
28
+ border: 1px solid var(--border);
29
+ border-radius: var(--radius-lg);
30
+ background: color-mix(in oklab, var(--muted) 40%, transparent);
31
+ font-family: var(--font-mono);
32
+ font-size: var(--text-sm);
33
+ }
34
+ .code {
35
+ padding: calc(var(--spacing) * 4) calc(var(--spacing) * 5);
36
+ overflow-x: auto;
37
+ white-space: pre;
38
+ }
39
+ ::slotted(pre) {
40
+ margin: 0;
41
+ }
42
+ .bar {
43
+ position: absolute;
44
+ top: calc(var(--spacing) * 1.5);
45
+ right: calc(var(--spacing) * 1.5);
46
+ display: flex;
47
+ align-items: center;
48
+ gap: calc(var(--spacing) * 2);
49
+ font-family: var(--font-sans);
50
+ font-size: var(--text-xs);
51
+ text-transform: uppercase;
52
+ color: var(--muted-foreground);
53
+ }
54
+ </style>
55
+
56
+ <div class="code" part="code"><slot></slot></div>
57
+ <div class="bar" part="bar">
58
+ <span><slot name="@language"></slot></span>
59
+ <ui-button variant="ghost" size="icon-sm" aria-label="Copy code" onclick="copyCode()">
60
+ <is-hidden when="#copy.done">⧉</is-hidden>
61
+ <is-visible when="#copy.done">✓</is-visible>
62
+ </ui-button>
63
+ </div>
64
+ </custom-element>
@@ -0,0 +1,90 @@
1
+ <custom-element name="ui-collapsible">
2
+ <script>
3
+ const props = defineProps({ open: prop.boolean().reflect(), disabled: prop.boolean() });
4
+
5
+ function toggled(details) {
6
+ if (details.open === props.open) return;
7
+ props.open = details.open;
8
+ dispatch("toggle");
9
+ }
10
+
11
+ function guard() {
12
+ return !props.disabled;
13
+ }
14
+ </script>
15
+
16
+ <style>
17
+ /* A double tap must not zoom the page. Set inside the shadow root, because a page-level
18
+ touch-action does not reach shadow content in iOS Safari. */
19
+ :host,
20
+ * {
21
+ touch-action: manipulation;
22
+ }
23
+ :host {
24
+ display: block;
25
+ }
26
+ summary {
27
+ list-style: none;
28
+ border-radius: var(--radius-md);
29
+ cursor: pointer;
30
+ outline: none;
31
+ }
32
+ summary::-webkit-details-marker {
33
+ display: none;
34
+ }
35
+ summary:focus-visible {
36
+ box-shadow: var(--focus-ring);
37
+ }
38
+ :host(:state(attr-disabled)) summary {
39
+ pointer-events: none;
40
+ opacity: 0.5;
41
+ }
42
+ </style>
43
+
44
+ <details _open="@open" ontoggle="toggled(this)">
45
+ <summary part="trigger" onclick="return guard()"><slot name="trigger"></slot></summary>
46
+ <slot></slot>
47
+ </details>
48
+ </custom-element>
49
+
50
+ <custom-element name="ui-collapsible-trigger" slot="trigger">
51
+ <style>
52
+ :host,
53
+ * {
54
+ touch-action: manipulation;
55
+ }
56
+ :host {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: space-between;
60
+ gap: calc(var(--spacing) * 4);
61
+ font-size: var(--text-sm);
62
+ font-weight: var(--font-weight-semibold);
63
+ }
64
+ ::slotted(svg) {
65
+ flex-shrink: 0;
66
+ width: calc(var(--spacing) * 4);
67
+ height: calc(var(--spacing) * 4);
68
+ }
69
+ </style>
70
+
71
+ <slot></slot>
72
+ </custom-element>
73
+
74
+ <custom-element name="ui-collapsible-content">
75
+ <style>
76
+ :host,
77
+ * {
78
+ touch-action: manipulation;
79
+ }
80
+ :host {
81
+ display: flex;
82
+ flex-direction: column;
83
+ gap: calc(var(--spacing) * 2);
84
+ padding-top: calc(var(--spacing) * 2);
85
+ font-size: var(--text-sm);
86
+ }
87
+ </style>
88
+
89
+ <slot></slot>
90
+ </custom-element>