vueless 1.3.7-beta.2 → 1.3.7-beta.4

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 (37) hide show
  1. package/components.d.ts +1 -0
  2. package/components.ts +1 -0
  3. package/constants.d.ts +2 -0
  4. package/constants.js +2 -0
  5. package/icons/storybook/help.svg +1 -0
  6. package/icons/storybook/logout.svg +1 -0
  7. package/package.json +2 -2
  8. package/ui.container-col/UCol.vue +0 -1
  9. package/ui.container-collapsible/UCollapsible.vue +190 -0
  10. package/ui.container-collapsible/config.ts +45 -0
  11. package/ui.container-collapsible/constants.ts +1 -0
  12. package/ui.container-collapsible/storybook/docs.mdx +17 -0
  13. package/ui.container-collapsible/storybook/stories.ts +238 -0
  14. package/ui.container-collapsible/tests/UCollapsible.test.ts +571 -0
  15. package/ui.container-collapsible/types.ts +57 -0
  16. package/ui.dropdown/UDropdown.vue +324 -0
  17. package/ui.dropdown/config.ts +27 -0
  18. package/ui.dropdown/constants.ts +1 -0
  19. package/ui.dropdown/storybook/docs.mdx +17 -0
  20. package/ui.dropdown/storybook/stories.ts +286 -0
  21. package/ui.dropdown/tests/UDropdown.test.ts +631 -0
  22. package/ui.dropdown/types.ts +127 -0
  23. package/ui.dropdown-badge/UDropdownBadge.vue +119 -227
  24. package/ui.dropdown-badge/config.ts +18 -15
  25. package/ui.dropdown-badge/storybook/stories.ts +13 -40
  26. package/ui.dropdown-badge/tests/UDropdownBadge.test.ts +201 -67
  27. package/ui.dropdown-button/UDropdownButton.vue +121 -226
  28. package/ui.dropdown-button/config.ts +32 -28
  29. package/ui.dropdown-button/storybook/stories.ts +15 -42
  30. package/ui.dropdown-button/tests/UDropdownButton.test.ts +189 -73
  31. package/ui.dropdown-link/UDropdownLink.vue +123 -233
  32. package/ui.dropdown-link/config.ts +15 -18
  33. package/ui.dropdown-link/storybook/stories.ts +31 -58
  34. package/ui.dropdown-link/tests/UDropdownLink.test.ts +190 -71
  35. package/ui.form-listbox/UListbox.vue +2 -3
  36. package/ui.form-listbox/config.ts +2 -2
  37. package/ui.form-select/config.ts +1 -1
package/components.d.ts CHANGED
@@ -44,6 +44,7 @@ export { default as URow } from "./ui.container-row/URow.vue";
44
44
  export { default as UGrid } from "./ui.container-grid/UGrid.vue";
45
45
  export { default as UGroup } from "./ui.container-group/UGroup.vue";
46
46
  export { default as UGroups } from "./ui.container-groups/UGroups.vue";
47
+ export { default as UCollapsible } from "./ui.container-collapsible/UCollapsible.vue";
47
48
  export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
48
49
  export { default as UAccordionItem } from "./ui.container-accordion-item/UAccordionItem.vue";
49
50
  export { default as UEmpty } from "./ui.container-empty/UEmpty.vue";
package/components.ts CHANGED
@@ -44,6 +44,7 @@ export { default as URow } from "./ui.container-row/URow.vue";
44
44
  export { default as UGrid } from "./ui.container-grid/UGrid.vue";
45
45
  export { default as UGroup } from "./ui.container-group/UGroup.vue";
46
46
  export { default as UGroups } from "./ui.container-groups/UGroups.vue";
47
+ export { default as UCollapsible } from "./ui.container-collapsible/UCollapsible.vue";
47
48
  export { default as UAccordion } from "./ui.container-accordion/UAccordion.vue";
48
49
  export { default as UAccordionItem } from "./ui.container-accordion-item/UAccordionItem.vue";
49
50
  export { default as UEmpty } from "./ui.container-empty/UEmpty.vue";
package/constants.d.ts CHANGED
@@ -145,6 +145,7 @@ export namespace COMPONENTS {
145
145
  let UButton: string;
146
146
  let ULink: string;
147
147
  let UToggle: string;
148
+ let UDropdown: string;
148
149
  let UDropdownButton: string;
149
150
  let UDropdownBadge: string;
150
151
  let UDropdownLink: string;
@@ -183,6 +184,7 @@ export namespace COMPONENTS {
183
184
  let UGrid: string;
184
185
  let UGroup: string;
185
186
  let UGroups: string;
187
+ let UCollapsible: string;
186
188
  let UAccordion: string;
187
189
  let UAccordionItem: string;
188
190
  let UEmpty: string;
package/constants.js CHANGED
@@ -249,6 +249,7 @@ export const COMPONENTS = {
249
249
  UToggle: "ui.button-toggle",
250
250
 
251
251
  /* Dropdowns */
252
+ UDropdown: "ui.dropdown",
252
253
  UDropdownButton: "ui.dropdown-button",
253
254
  UDropdownBadge: "ui.dropdown-badge",
254
255
  UDropdownLink: "ui.dropdown-link",
@@ -293,6 +294,7 @@ export const COMPONENTS = {
293
294
  UGrid: "ui.container-grid",
294
295
  UGroup: "ui.container-group",
295
296
  UGroups: "ui.container-groups",
297
+ UCollapsible: "ui.container-collapsible",
296
298
  UAccordion: "ui.container-accordion",
297
299
  UAccordionItem: "ui.container-accordion-item",
298
300
  UEmpty: "ui.container-empty",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="M483.52-247q16.48 0 28.2-11.72 11.71-11.71 11.71-28.35 0-16.63-11.71-28.19-11.72-11.57-28.32-11.57t-28.19 11.55q-11.6 11.54-11.6 28.33 0 16.52 11.63 28.23Q466.87-247 483.52-247Zm-36.91-146h62.59q0-25.52 6.5-47.02 6.5-21.5 39.78-49.02 30.52-25.05 43.4-50.34 12.88-25.29 12.88-55.69 0-53.69-34.09-86.05t-91.19-32.36q-49.72 0-88.06 25.46-38.33 25.45-55.81 69.45l56.82 21.4q11.24-28.24 32.88-43.62 21.64-15.38 50.21-15.38 31.73 0 51.83 17.58 20.11 17.58 20.11 45.47 0 21.12-12.64 40.38-12.65 19.26-36.45 39.07-29.52 25.52-44.14 51.75-14.62 26.24-14.62 68.92Zm33.42 318.98q-83.46 0-157.54-31.88-74.07-31.88-129.39-87.2-55.32-55.32-87.2-129.36-31.88-74.04-31.88-157.51 0-84.46 31.88-158.54 31.88-74.07 87.16-128.9 55.28-54.84 129.34-86.82 74.06-31.99 157.55-31.99 84.48 0 158.59 31.97 74.1 31.97 128.91 86.77 54.82 54.8 86.79 128.88 31.98 74.08 31.98 158.6 0 83.5-31.99 157.57-31.98 74.07-86.82 129.36-54.83 55.29-128.87 87.17-74.04 31.88-158.51 31.88Zm-.03-68.13q141.04 0 239.45-98.75 98.4-98.76 98.4-239.1 0-141.04-98.4-239.45-98.41-98.4-239.57-98.4-140.16 0-238.95 98.4-98.78 98.41-98.78 239.57 0 140.16 98.75 238.95 98.76 98.78 239.1 98.78ZM480-480Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 -960 960 960"><path d="M182.15-114.02q-27.6 0-47.86-20.27-20.27-20.26-20.27-47.86v-595.7q0-27.7 20.27-48.03 20.26-20.34 47.86-20.34h298.28v68.37H182.15v595.7h298.28v68.13H182.15Zm481.46-182.37-48.74-48.5 100.8-101.04h-357.1v-68.14h355.1l-100.8-101.04 48.74-48.5L846.22-479 663.61-296.39Z"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vueless",
3
- "version": "1.3.7-beta.2",
3
+ "version": "1.3.7-beta.4",
4
4
  "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",
5
5
  "author": "Johnny Grid <hello@vueless.com> (https://vueless.com)",
6
6
  "homepage": "https://vueless.com",
@@ -57,7 +57,7 @@
57
57
  "@vue/eslint-config-typescript": "^14.6.0",
58
58
  "@vue/test-utils": "^2.4.6",
59
59
  "@vue/tsconfig": "^0.7.0",
60
- "@vueless/storybook": "^1.3.16",
60
+ "@vueless/storybook": "^1.3.18",
61
61
  "eslint": "^9.32.0",
62
62
  "eslint-plugin-storybook": "^10.0.2",
63
63
  "eslint-plugin-vue": "^10.3.0",
@@ -28,7 +28,6 @@ defineExpose({
28
28
  * Get element / nested component attributes for each config token ✨
29
29
  * Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
30
30
  */
31
-
32
31
  const { getDataTest, wrapperAttrs } = useUI<Config>(defaultConfig);
33
32
  </script>
34
33
 
@@ -0,0 +1,190 @@
1
+ <script setup lang="ts">
2
+ import { nextTick, computed, ref, useId, useTemplateRef, watch } from "vue";
3
+
4
+ import { useUI } from "../composables/useUI";
5
+ import { getDefaults } from "../utils/ui";
6
+
7
+ import vClickOutside from "../v.click-outside/vClickOutside";
8
+
9
+ import defaultConfig from "./config";
10
+ import { COMPONENT_NAME } from "./constants";
11
+
12
+ import type { Props, Config } from "./types";
13
+
14
+ defineOptions({ inheritAttrs: false });
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ ...getDefaults<Props, Config>(defaultConfig, COMPONENT_NAME),
18
+ });
19
+
20
+ const emit = defineEmits([
21
+ /**
22
+ * Triggers when the opened state changes.
23
+ * @property {boolean} value
24
+ */
25
+ "update:open",
26
+
27
+ /**
28
+ * Triggers when collapsible is opened.
29
+ */
30
+ "open",
31
+
32
+ /**
33
+ * Triggers when collapsible is closed.
34
+ */
35
+ "close",
36
+ ]);
37
+
38
+ const internalIsOpened = ref(false);
39
+ const isClickingContent = ref(false);
40
+
41
+ const wrapperRef = useTemplateRef<HTMLDivElement>("wrapper");
42
+ const elementId = props.id || useId();
43
+
44
+ watch(
45
+ () => props.open,
46
+ (newValue) => {
47
+ if (newValue !== undefined) {
48
+ internalIsOpened.value = newValue;
49
+ }
50
+ },
51
+ { immediate: true },
52
+ );
53
+
54
+ const isOpened = computed({
55
+ get: () => internalIsOpened.value,
56
+ set: (value) => {
57
+ internalIsOpened.value = value;
58
+ emit("update:open", value);
59
+ },
60
+ });
61
+
62
+ function handleClickOutside() {
63
+ if (isClickingContent.value || !props.closeOnOutside) {
64
+ return;
65
+ }
66
+
67
+ hide();
68
+ }
69
+
70
+ function toggle() {
71
+ if (props.disabled) return;
72
+
73
+ isOpened.value = !isOpened.value;
74
+
75
+ isOpened.value ? emit("open") : emit("close");
76
+ }
77
+
78
+ function hide() {
79
+ isOpened.value = false;
80
+
81
+ emit("close");
82
+ }
83
+
84
+ function show() {
85
+ if (props.disabled) return;
86
+
87
+ isOpened.value = true;
88
+
89
+ emit("open");
90
+ }
91
+
92
+ function onContentClick() {
93
+ if (!props.closeOnContent) {
94
+ isClickingContent.value = true;
95
+
96
+ nextTick(() => {
97
+ isClickingContent.value = false;
98
+ });
99
+
100
+ return;
101
+ }
102
+
103
+ hide();
104
+ }
105
+
106
+ defineExpose({
107
+ /**
108
+ * A reference to the component's wrapper element for direct DOM manipulation.
109
+ * @property {HTMLDivElement}
110
+ */
111
+ wrapperRef,
112
+
113
+ /**
114
+ * Hides the collapsible content.
115
+ * @property {function}
116
+ */
117
+ hide,
118
+
119
+ /**
120
+ * Shows the collapsible content.
121
+ * @property {function}
122
+ */
123
+ show,
124
+
125
+ /**
126
+ * Toggles the collapsible visibility.
127
+ * @property {function}
128
+ */
129
+ toggle,
130
+
131
+ /**
132
+ * Indicates whether the collapsible is opened.
133
+ * @property {boolean}
134
+ */
135
+ isOpened,
136
+ });
137
+
138
+ /**
139
+ * Get element / nested component attributes for each config token ✨
140
+ * Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
141
+ */
142
+ const mutatedProps = computed(() => ({
143
+ /* component state, not a props */
144
+ opened: isOpened.value,
145
+ }));
146
+
147
+ const { getDataTest, config, wrapperAttrs, contentAttrs } = useUI<Config>(
148
+ defaultConfig,
149
+ mutatedProps,
150
+ );
151
+ </script>
152
+
153
+ <template>
154
+ <div
155
+ :id="elementId"
156
+ ref="wrapper"
157
+ v-click-outside="handleClickOutside"
158
+ v-bind="wrapperAttrs"
159
+ tabindex="0"
160
+ :data-test="getDataTest()"
161
+ @click="toggle"
162
+ @keydown.enter="toggle"
163
+ >
164
+ <!--
165
+ @slot Use it to add custom trigger element for the collapsible.
166
+ @binding {boolean} opened
167
+ -->
168
+ <slot :opened="isOpened" />
169
+
170
+ <Transition v-bind="config.contentTransition">
171
+ <!--
172
+ @slot Use it to add collapsible content.
173
+ @binding {boolean} opened
174
+ -->
175
+ <div
176
+ v-if="isOpened"
177
+ v-bind="contentAttrs"
178
+ :data-test="getDataTest('content')"
179
+ @click.stop="onContentClick"
180
+ >
181
+ <!--
182
+ @slot Use it to add some content need to be shown.
183
+ @binding {boolean} opened
184
+ @binding {string} contentClasses
185
+ -->
186
+ <slot name="content" :opened="isOpened" :content-classes="contentAttrs.class" />
187
+ </div>
188
+ </Transition>
189
+ </div>
190
+ </template>
@@ -0,0 +1,45 @@
1
+ export default /*tw*/ {
2
+ wrapper: {
3
+ base: `
4
+ relative inline-block h-max rounded-medium transition cursor-pointer outline-transparent
5
+ focus-visible:outline-medium focus-visible:outline-offset-2 focus-visible:outline-primary`,
6
+ variants: {
7
+ disabled: {
8
+ true: "cursor-not-allowed",
9
+ },
10
+ },
11
+ },
12
+ content: {
13
+ base: "z-10 w-max",
14
+ variants: {
15
+ absolute: {
16
+ true: "absolute",
17
+ false: "",
18
+ },
19
+ yPosition: {
20
+ top: "bottom-full mb-1",
21
+ bottom: "top-full mt-1",
22
+ },
23
+ xPosition: {
24
+ left: "left-0",
25
+ right: "right-0",
26
+ },
27
+ },
28
+ },
29
+ contentTransition: {
30
+ enterActiveClass: "ease-out duration-200",
31
+ enterFromClass: "opacity-0 scale-95",
32
+ enterToClass: "opacity-100 scale-100",
33
+ leaveActiveClass: "ease-in duration-150",
34
+ leaveFromClass: "opacity-100 scale-100",
35
+ leaveToClass: "opacity-0 scale-95",
36
+ },
37
+ defaults: {
38
+ absolute: true,
39
+ yPosition: "bottom",
40
+ xPosition: "left",
41
+ closeOnOutside: true,
42
+ closeOnContent: false,
43
+ disabled: false,
44
+ },
45
+ };
@@ -0,0 +1 @@
1
+ export const COMPONENT_NAME = "UCollapsible";
@@ -0,0 +1,17 @@
1
+ import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/addon-docs/blocks";
2
+ import { getSource } from "../../utils/storybook.ts";
3
+
4
+ import * as stories from "./stories.ts";
5
+ import defaultConfig from "../config.ts?raw"
6
+
7
+ <Meta of={stories} />
8
+ <Title of={stories} />
9
+ <Subtitle of={stories} />
10
+ <Description of={stories} />
11
+ <Primary of={stories} />
12
+ <Controls of={stories.Default} />
13
+ <Stories of={stories} />
14
+
15
+ ## Default config
16
+ <Source code={getSource(defaultConfig)} language="jsx" dark />
17
+
@@ -0,0 +1,238 @@
1
+ import { ref } from "vue";
2
+ import {
3
+ getArgs,
4
+ getArgTypes,
5
+ getSlotNames,
6
+ getSlotsFragment,
7
+ getDocsDescription,
8
+ } from "../../utils/storybook";
9
+
10
+ import UCollapsible from "../UCollapsible.vue";
11
+ import UButton from "../../ui.button/UButton.vue";
12
+ import UCard from "../../ui.container-card/UCard.vue";
13
+ import URow from "../../ui.container-row/URow.vue";
14
+ import UCol from "../../ui.container-col/UCol.vue";
15
+ import UIcon from "../../ui.image-icon/UIcon.vue";
16
+ import UAvatar from "../../ui.image-avatar/UAvatar.vue";
17
+ import UDivider from "../../ui.container-divider/UDivider.vue";
18
+ import UText from "../../ui.text-block/UText.vue";
19
+
20
+ import type { Meta, StoryFn } from "@storybook/vue3-vite";
21
+ import type { Props } from "../types";
22
+
23
+ interface UCollapsibleArgs extends Props {
24
+ slotTemplate?: string;
25
+ enum: "yPosition" | "xPosition";
26
+ class?: string;
27
+ label?: string;
28
+ rowClass?: string;
29
+ }
30
+
31
+ const defaultTemplate = `
32
+ <template #default>
33
+ <UButton label="John Doe" variant="outlined" size="sm" />
34
+ </template>
35
+
36
+ <template #content>
37
+ <UCard class="min-w-[280px] !p-2.5">
38
+ <URow align="center" gap="sm" class="mb-2">
39
+ <UAvatar label="John Doe" size="md" />
40
+ <UCol gap="none">
41
+ <UText size="sm">John Doe</UText>
42
+ <UText variant="lifted" size="xs">john.doe@example.com</UText>
43
+ </UCol>
44
+ </URow>
45
+ <UDivider />
46
+ <UCol gap="2xs" class="mt-2">
47
+ <UButton
48
+ label="Settings"
49
+ variant="subtle"
50
+ size="sm"
51
+ left-icon="settings"
52
+ color="neutral"
53
+ block
54
+ class="justify-start"
55
+ />
56
+ <UButton
57
+ label="Help & Support"
58
+ variant="subtle"
59
+ size="sm"
60
+ left-icon="help"
61
+ color="info"
62
+ block
63
+ class="justify-start"
64
+ />
65
+ <UButton
66
+ label="Sign Out"
67
+ variant="subtle"
68
+ size="sm"
69
+ left-icon="logout"
70
+ color="error"
71
+ block
72
+ class="justify-start"
73
+ />
74
+ </UCol>
75
+ </UCard>
76
+ </template>
77
+ `;
78
+
79
+ export default {
80
+ id: "5270",
81
+ title: "Containers / Collapsible",
82
+ component: UCollapsible,
83
+ args: {
84
+ slotTemplate: defaultTemplate,
85
+ },
86
+ argTypes: {
87
+ ...getArgTypes(UCollapsible.__name),
88
+ },
89
+ parameters: {
90
+ docs: {
91
+ ...getDocsDescription(UCollapsible.__name),
92
+ story: {
93
+ height: "300px",
94
+ },
95
+ },
96
+ },
97
+ } as Meta;
98
+
99
+ const DefaultTemplate: StoryFn<UCollapsibleArgs> = (args: UCollapsibleArgs) => ({
100
+ components: { UCollapsible, UButton, UCard, UIcon, UAvatar, UDivider, UText, UCol, URow },
101
+ setup: () => ({ args, slots: getSlotNames(UCollapsible.__name) }),
102
+ template: `
103
+ <UCollapsible v-bind="args">
104
+ ${args.slotTemplate || getSlotsFragment("")}
105
+ </UCollapsible>
106
+ `,
107
+ });
108
+
109
+ const EnumTemplate: StoryFn<UCollapsibleArgs> = (args: UCollapsibleArgs, { argTypes }) => ({
110
+ components: { UCollapsible, UButton, UCard, UIcon, UAvatar, UDivider, UText, UCol, URow },
111
+ setup: () => {
112
+ const openStates = ref<Record<string, boolean>>({});
113
+
114
+ return { args, argTypes, getArgs, openStates };
115
+ },
116
+ template: `
117
+ <URow :class="args.rowClass">
118
+ <UCollapsible
119
+ v-for="option in argTypes?.[args.enum]?.options"
120
+ v-bind="getArgs(args, option)"
121
+ v-model:open="openStates[option]"
122
+ :key="option"
123
+ >
124
+ <template #default>
125
+ <UButton :label="option" variant="outlined" size="sm" />
126
+ </template>
127
+
128
+ <template #content>
129
+ <UCard class="min-w-[280px] !p-2.5">
130
+ <URow align="center" gap="sm" class="mb-2">
131
+ <UAvatar label="John Doe" size="md" />
132
+ <UCol gap="none">
133
+ <UText size="sm">John Doe</UText>
134
+ <UText variant="lifted" size="xs">john.doe@example.com</UText>
135
+ </UCol>
136
+ </URow>
137
+ <UDivider />
138
+ <UCol gap="2xs" class="mt-2">
139
+ <UButton
140
+ label="Settings"
141
+ variant="subtle"
142
+ size="sm"
143
+ left-icon="settings"
144
+ color="neutral"
145
+ block
146
+ class="justify-start"
147
+ />
148
+ <UButton
149
+ label="Help & Support"
150
+ variant="subtle"
151
+ size="sm"
152
+ left-icon="help"
153
+ color="info"
154
+ block
155
+ class="justify-start"
156
+ />
157
+ <UButton
158
+ label="Sign Out"
159
+ variant="subtle"
160
+ size="sm"
161
+ left-icon="logout"
162
+ color="error"
163
+ block
164
+ class="justify-start"
165
+ />
166
+ </UCol>
167
+ </UCard>
168
+ </template>
169
+ </UCollapsible>
170
+ </URow>
171
+ `,
172
+ });
173
+
174
+ export const Default = DefaultTemplate.bind({});
175
+ Default.args = {};
176
+
177
+ export const Disabled: StoryFn<UCollapsibleArgs> = (args) => ({
178
+ components: { UCollapsible, UButton, UCard, UDivider, UText, UIcon, UCol, URow },
179
+ setup() {
180
+ return { args };
181
+ },
182
+ template: `
183
+ <UCollapsible disabled>
184
+ <UButton label="John Doe" disabled variant="subtle" size="sm" />
185
+ </UCollapsible>
186
+ `,
187
+ });
188
+ Disabled.parameters = {
189
+ docs: {
190
+ story: {
191
+ height: "120px",
192
+ },
193
+ },
194
+ };
195
+
196
+ export const XPosition = EnumTemplate.bind({});
197
+ XPosition.args = {
198
+ enum: "xPosition",
199
+ label: "{enumValue}",
200
+ rowClass: "w-full justify-center gap-96",
201
+ };
202
+
203
+ export const YPosition = EnumTemplate.bind({});
204
+ YPosition.args = { enum: "yPosition", label: "{enumValue}" };
205
+ YPosition.parameters = {
206
+ storyClasses: "h-[500px] flex items-center px-6 pt-8 pb-12",
207
+ };
208
+
209
+ export const NonAbsolute: StoryFn<UCollapsibleArgs> = (args) => ({
210
+ components: { UCollapsible, UButton, UCard, UCol, UDivider, UText },
211
+ setup() {
212
+ return { args };
213
+ },
214
+ template: `
215
+ <UCol gap="md">
216
+ <UCollapsible :absolute="false">
217
+ <template #default="{ opened }">
218
+ <UButton :label="opened ? 'Close' : 'Open'" />
219
+ </template>
220
+ <template #content>
221
+ <UCard
222
+ title="Non-Absolute Content"
223
+ description="This content is not positioned absolutely, so it flows with the document."
224
+ />
225
+ </template>
226
+ </UCollapsible>
227
+ <div class="p-4 border border-gray-300 rounded">
228
+ <p>This content appears below the collapsible and will be pushed down when it opens.</p>
229
+ </div>
230
+ </UCol>
231
+ `,
232
+ });
233
+
234
+ export const NoCloseOnOutside = DefaultTemplate.bind({});
235
+ NoCloseOnOutside.args = { closeOnOutside: false };
236
+
237
+ export const CloseOnContent = DefaultTemplate.bind({});
238
+ CloseOnContent.args = { closeOnContent: true };