@prsm/mono-components 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.
Files changed (90) hide show
  1. package/.claude/settings.local.json +13 -0
  2. package/.lore +83 -0
  3. package/histoire.config.js +43 -0
  4. package/package.json +39 -0
  5. package/postcss.config.js +6 -0
  6. package/src/components/Badge.vue +36 -0
  7. package/src/components/Button.vue +44 -0
  8. package/src/components/Checkbox.vue +51 -0
  9. package/src/components/CheckboxCards.vue +61 -0
  10. package/src/components/CodeEditor.vue +299 -0
  11. package/src/components/Collapsible.vue +69 -0
  12. package/src/components/CollapsibleGroup.vue +38 -0
  13. package/src/components/Combobox.vue +179 -0
  14. package/src/components/ContextMenu.vue +65 -0
  15. package/src/components/ContextMenuPanel.vue +115 -0
  16. package/src/components/DataTable.vue +326 -0
  17. package/src/components/Dropdown.vue +127 -0
  18. package/src/components/GhostInput.vue +29 -0
  19. package/src/components/Input.vue +23 -0
  20. package/src/components/KeyValue.vue +149 -0
  21. package/src/components/LabeledTextarea.vue +64 -0
  22. package/src/components/LabeledTextareaGroup.vue +14 -0
  23. package/src/components/Mention.vue +79 -0
  24. package/src/components/Modal.vue +109 -0
  25. package/src/components/MultiCombobox.vue +209 -0
  26. package/src/components/NavTree.vue +98 -0
  27. package/src/components/NumberInput.vue +128 -0
  28. package/src/components/PopConfirm.vue +94 -0
  29. package/src/components/Popover.vue +53 -0
  30. package/src/components/RadioCards.vue +37 -0
  31. package/src/components/RadioGroup.vue +57 -0
  32. package/src/components/RangeSlider.vue +165 -0
  33. package/src/components/ScrollBox.vue +78 -0
  34. package/src/components/SectionHeader.vue +18 -0
  35. package/src/components/Select.vue +187 -0
  36. package/src/components/Switch.vue +85 -0
  37. package/src/components/Tabs.vue +34 -0
  38. package/src/components/TagInput.vue +80 -0
  39. package/src/components/Textarea.vue +97 -0
  40. package/src/components/ToastContainer.vue +104 -0
  41. package/src/components/ToggleButtons.vue +45 -0
  42. package/src/components/ToggleGroup.vue +30 -0
  43. package/src/components/Tooltip.vue +56 -0
  44. package/src/components/Tree.vue +188 -0
  45. package/src/composables/toast.js +54 -0
  46. package/src/composables/useClickOutside.js +23 -0
  47. package/src/composables/useMention.js +291 -0
  48. package/src/composables/usePointerDrag.js +39 -0
  49. package/src/histoire-setup.js +1 -0
  50. package/src/index.js +43 -0
  51. package/src/style.css +96 -0
  52. package/stories/Badge.story.vue +24 -0
  53. package/stories/Button.story.vue +45 -0
  54. package/stories/Checkbox.story.vue +31 -0
  55. package/stories/CheckboxCards.story.vue +51 -0
  56. package/stories/CodeEditor.story.vue +71 -0
  57. package/stories/Collapsible.story.vue +84 -0
  58. package/stories/Combobox.story.vue +44 -0
  59. package/stories/ContextMenu.story.vue +59 -0
  60. package/stories/DataTable.story.vue +185 -0
  61. package/stories/Dropdown.story.vue +49 -0
  62. package/stories/GhostInput.story.vue +24 -0
  63. package/stories/Input.story.vue +23 -0
  64. package/stories/KeyValue.story.vue +104 -0
  65. package/stories/LabeledTextarea.story.vue +44 -0
  66. package/stories/Mention.story.vue +166 -0
  67. package/stories/Modal.story.vue +86 -0
  68. package/stories/MultiCombobox.story.vue +76 -0
  69. package/stories/NavTree.story.vue +184 -0
  70. package/stories/NumberInput.story.vue +31 -0
  71. package/stories/Overview.story.vue +85 -0
  72. package/stories/PopConfirm.story.vue +39 -0
  73. package/stories/RadioCards.story.vue +66 -0
  74. package/stories/RadioGroup.story.vue +52 -0
  75. package/stories/RangeSlider.story.vue +75 -0
  76. package/stories/ScrollBox.story.vue +54 -0
  77. package/stories/SectionHeader.story.vue +22 -0
  78. package/stories/Select.story.vue +34 -0
  79. package/stories/Switch.story.vue +42 -0
  80. package/stories/Tabs.story.vue +34 -0
  81. package/stories/TagInput.story.vue +54 -0
  82. package/stories/Textarea.story.vue +28 -0
  83. package/stories/Toast.story.vue +28 -0
  84. package/stories/ToggleButtons.story.vue +57 -0
  85. package/stories/ToggleGroup.story.vue +34 -0
  86. package/stories/Tooltip.story.vue +55 -0
  87. package/stories/Tree.story.vue +115 -0
  88. package/tailwind.config.js +9 -0
  89. package/tailwind.preset.js +79 -0
  90. package/vite.config.js +6 -0
@@ -0,0 +1,75 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import { logEvent } from "histoire/client"
4
+ import RangeSlider from "../src/components/RangeSlider.vue"
5
+
6
+ const opacity = ref(50)
7
+ const volume = ref(75)
8
+ const temperature = ref(0.7)
9
+ const rotation = ref(0)
10
+
11
+ function handleUpdate(name, value) {
12
+ logEvent("update:modelValue", { name, value })
13
+ }
14
+ </script>
15
+
16
+ <template>
17
+ <Story title="RangeSlider">
18
+ <Variant title="Basic">
19
+ <div class="flex flex-col gap-3 w-[300px]">
20
+ <RangeSlider
21
+ v-model="opacity"
22
+ :min="0"
23
+ :max="100"
24
+ label="Opacity"
25
+ @update:model-value="v => handleUpdate('opacity', v)"
26
+ />
27
+ <RangeSlider
28
+ v-model="volume"
29
+ :min="0"
30
+ :max="100"
31
+ label="Volume"
32
+ @update:model-value="v => handleUpdate('volume', v)"
33
+ />
34
+ </div>
35
+ <template #controls>
36
+ <div class="text-xs text-fg-2 p-2">
37
+ opacity: {{ opacity }}, volume: {{ volume }}
38
+ </div>
39
+ </template>
40
+ </Variant>
41
+ <Variant title="Float Precision">
42
+ <div class="w-[300px]">
43
+ <RangeSlider
44
+ v-model="temperature"
45
+ :min="0"
46
+ :max="2"
47
+ :step="0.01"
48
+ label="Temperature"
49
+ @update:model-value="v => handleUpdate('temperature', v)"
50
+ />
51
+ </div>
52
+ </Variant>
53
+ <Variant title="Negative Range">
54
+ <div class="w-[300px]">
55
+ <RangeSlider
56
+ v-model="rotation"
57
+ :min="-180"
58
+ :max="180"
59
+ label="Rotation"
60
+ @update:model-value="v => handleUpdate('rotation', v)"
61
+ />
62
+ </div>
63
+ </Variant>
64
+ <Variant title="No Label">
65
+ <div class="w-[300px]">
66
+ <RangeSlider
67
+ v-model="opacity"
68
+ :min="0"
69
+ :max="100"
70
+ @update:model-value="v => handleUpdate('opacity', v)"
71
+ />
72
+ </div>
73
+ </Variant>
74
+ </Story>
75
+ </template>
@@ -0,0 +1,54 @@
1
+ <script setup>
2
+ import ScrollBox from "../src/components/ScrollBox.vue"
3
+ </script>
4
+
5
+ <template>
6
+ <Story title="ScrollBox">
7
+ <Variant title="Vertical">
8
+ <ScrollBox style="height: 200px" class="p-3 bg-1 border border-line rounded-sm">
9
+ <p class="text-base text-fg-1 mb-3">
10
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
11
+ tempor incididunt ut labore et dolore magna aliqua. Sed vulputate odio
12
+ ut enim. Magnis dis parturient montes nascetur ridiculus mus. Ultricies
13
+ mi eget mauris pharetra et. Massa sapien faucibus et molestie ac feugiat
14
+ sed lectus. Tempus imperdiet nulla malesuada pellentesque elit. Sit amet
15
+ aliquam id diam. Aliquam ultrices sagittis orci a. Urna nec tincidunt
16
+ praesent semper feugiat nibh sed pulvinar. Sit amet mauris commodo quis
17
+ imperdiet. Aliquet enim facilisis gravida neque convallis a cras semper.
18
+ </p>
19
+ <p class="text-base text-fg-1 mb-3">
20
+ Vitae nunc sed velit dignissim sodales ut eu. Pretium quam vulputate
21
+ dignissim suspendisse in est. Duis ut diam quam nulla porttitor massa id
22
+ neque aliquam. Volutpat ac tincidunt vitae semper quis lectus nulla at.
23
+ Ac tincidunt vitae semper quis lectus nulla at. Quis hendrerit dolor
24
+ magna egest est. Feugiat in ante metus dictum at tempor commodo
25
+ ullamcorper a. Quis auctor elit sed vulputate mi sit.
26
+ </p>
27
+ <p class="text-base text-fg-1">
28
+ Egestas dui id ornare arcu odio ut sem nulla. Potenti nullam ac tortor
29
+ vitae purus faucibus ornare suspendisse sed. Sagittis id consectetur
30
+ purus ut faucibus pulvinar elementum integer. Amet venenatis urna cursus
31
+ eget nunc scelerisque viverra mauris. Morbi tempus iaculis urna id
32
+ volutpat lacus laoreet non.
33
+ </p>
34
+ </ScrollBox>
35
+ </Variant>
36
+ <Variant title="Horizontal">
37
+ <ScrollBox horizontal style="height: 100px; width: 300px" class="p-3 bg-1 border border-line rounded-sm">
38
+ <div style="width: 800px">
39
+ <p class="text-base text-fg-1 whitespace-nowrap">
40
+ This content is wider than the container and scrolls horizontally.
41
+ Keep going to the right to see more content that overflows the scroll box.
42
+ </p>
43
+ </div>
44
+ </ScrollBox>
45
+ </Variant>
46
+ <Variant title="Max Height List">
47
+ <ScrollBox style="max-height: 150px" class="bg-1 border border-line rounded-sm">
48
+ <div v-for="i in 20" :key="i" class="px-3 py-1 text-base text-fg-1 border-b border-line-subtle">
49
+ Item {{ i }}
50
+ </div>
51
+ </ScrollBox>
52
+ </Variant>
53
+ </Story>
54
+ </template>
@@ -0,0 +1,22 @@
1
+ <script setup>
2
+ import SectionHeader from "../src/components/SectionHeader.vue"
3
+ import Button from "../src/components/Button.vue"
4
+ </script>
5
+
6
+ <template>
7
+ <Story title="SectionHeader">
8
+ <Variant title="Label Only">
9
+ <SectionHeader label="Assertions" />
10
+ </Variant>
11
+ <Variant title="With Description">
12
+ <SectionHeader label="Assertions" description="conditions that must pass for this test case to succeed" />
13
+ </Variant>
14
+ <Variant title="With Actions">
15
+ <SectionHeader label="Assertions" description="conditions that must pass for this test case to succeed">
16
+ <template #actions>
17
+ <Button>+ add assertion</Button>
18
+ </template>
19
+ </SectionHeader>
20
+ </Variant>
21
+ </Story>
22
+ </template>
@@ -0,0 +1,34 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import Select from "../src/components/Select.vue"
4
+
5
+ const simple = ref(null)
6
+ const withObjects = ref("b")
7
+ </script>
8
+
9
+ <template>
10
+ <Story title="Select">
11
+ <Variant title="String Options">
12
+ <Select v-model="simple" :options="['apple', 'banana', 'cherry', 'dragonfruit']" />
13
+ <template #controls>
14
+ <div class="text-xs text-fg-2 p-2">value: {{ simple }}</div>
15
+ </template>
16
+ </Variant>
17
+ <Variant title="Object Options">
18
+ <Select
19
+ v-model="withObjects"
20
+ :options="[
21
+ { value: 'a', label: 'Option A' },
22
+ { value: 'b', label: 'Option B' },
23
+ { value: 'c', label: 'Option C' }
24
+ ]"
25
+ />
26
+ <template #controls>
27
+ <div class="text-xs text-fg-2 p-2">value: {{ withObjects }}</div>
28
+ </template>
29
+ </Variant>
30
+ <Variant title="Custom Placeholder">
31
+ <Select v-model="simple" :options="['one', 'two', 'three']" placeholder="pick one..." />
32
+ </Variant>
33
+ </Story>
34
+ </template>
@@ -0,0 +1,42 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import Switch from "../src/components/Switch.vue"
4
+
5
+ const on = ref(false)
6
+ const features = ref({ darkMode: true, notifications: false, autoSave: true })
7
+ </script>
8
+
9
+ <template>
10
+ <Story title="Switch">
11
+ <Variant title="Default">
12
+ <Switch v-model="on" />
13
+ <template #controls>
14
+ <div class="text-xs text-fg-2 p-2">value: {{ on }}</div>
15
+ </template>
16
+ </Variant>
17
+ <Variant title="States">
18
+ <div class="flex items-center gap-4">
19
+ <Switch :model-value="false" />
20
+ <Switch :model-value="true" />
21
+ <Switch :model-value="false" disabled />
22
+ <Switch :model-value="true" disabled />
23
+ </div>
24
+ </Variant>
25
+ <Variant title="Settings List">
26
+ <div class="flex flex-col gap-2 max-w-xs">
27
+ <label class="flex items-center justify-between px-2 py-1 rounded-sm hover:bg-2 cursor-pointer">
28
+ <span class="text-base text-fg-0">Dark mode</span>
29
+ <Switch v-model="features.darkMode" />
30
+ </label>
31
+ <label class="flex items-center justify-between px-2 py-1 rounded-sm hover:bg-2 cursor-pointer">
32
+ <span class="text-base text-fg-0">Notifications</span>
33
+ <Switch v-model="features.notifications" />
34
+ </label>
35
+ <label class="flex items-center justify-between px-2 py-1 rounded-sm hover:bg-2 cursor-pointer">
36
+ <span class="text-base text-fg-0">Auto save</span>
37
+ <Switch v-model="features.autoSave" />
38
+ </label>
39
+ </div>
40
+ </Variant>
41
+ </Story>
42
+ </template>
@@ -0,0 +1,34 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import Tabs from "../src/components/Tabs.vue"
4
+
5
+ const active = ref("all")
6
+ </script>
7
+
8
+ <template>
9
+ <Story title="Tabs">
10
+ <Variant title="Basic">
11
+ <Tabs
12
+ v-model="active"
13
+ :tabs="[
14
+ { key: 'all', label: 'All' },
15
+ { key: 'active', label: 'Active' },
16
+ { key: 'archived', label: 'Archived' }
17
+ ]"
18
+ />
19
+ <template #controls>
20
+ <div class="text-xs text-fg-2 p-2">active: {{ active }}</div>
21
+ </template>
22
+ </Variant>
23
+ <Variant title="With Icons and Counts">
24
+ <Tabs
25
+ v-model="active"
26
+ :tabs="[
27
+ { key: 'all', icon: 'material-symbols:list', label: 'All', count: 42 },
28
+ { key: 'active', icon: 'material-symbols:check-circle', label: 'Active', count: 12 },
29
+ { key: 'archived', icon: 'material-symbols:archive', label: 'Archived', count: 30 }
30
+ ]"
31
+ />
32
+ </Variant>
33
+ </Story>
34
+ </template>
@@ -0,0 +1,54 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import { logEvent } from "histoire/client"
4
+ import TagInput from "../src/components/TagInput.vue"
5
+
6
+ const colors = ref(["red", "blue", "green"])
7
+ const empty = ref([])
8
+ const sentiments = ref(["positive", "neutral", "negative"])
9
+
10
+ function handleUpdate(name, value) {
11
+ logEvent("update:modelValue", { name, value })
12
+ }
13
+ </script>
14
+
15
+ <template>
16
+ <Story title="TagInput">
17
+ <Variant title="With Tags">
18
+ <div class="w-[300px]">
19
+ <TagInput
20
+ v-model="colors"
21
+ placeholder="type and press enter..."
22
+ @update:model-value="v => handleUpdate('colors', v)"
23
+ />
24
+ </div>
25
+ <template #controls>
26
+ <div class="text-xs text-fg-2 p-2">tags: {{ colors.join(', ') }}</div>
27
+ </template>
28
+ </Variant>
29
+ <Variant title="Empty">
30
+ <div class="w-[300px]">
31
+ <TagInput
32
+ v-model="empty"
33
+ placeholder="add tags..."
34
+ @update:model-value="v => handleUpdate('empty', v)"
35
+ />
36
+ </div>
37
+ <template #controls>
38
+ <div class="text-xs text-fg-2 p-2">tags: {{ empty.length ? empty.join(', ') : 'none' }}</div>
39
+ </template>
40
+ </Variant>
41
+ <Variant title="Enum Options">
42
+ <div class="w-[300px]">
43
+ <TagInput
44
+ v-model="sentiments"
45
+ placeholder="type option, enter to add"
46
+ @update:model-value="v => handleUpdate('sentiments', v)"
47
+ />
48
+ </div>
49
+ <template #controls>
50
+ <div class="text-xs text-fg-2 p-2">options: {{ sentiments.join(', ') }}</div>
51
+ </template>
52
+ </Variant>
53
+ </Story>
54
+ </template>
@@ -0,0 +1,28 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import Textarea from "../src/components/Textarea.vue"
4
+
5
+ const basic = ref("")
6
+ const prefilled = ref("This textarea has some initial content that was set before mount. It should auto-grow to fit this text without any scrollbar appearing.")
7
+ const growing = ref("")
8
+ </script>
9
+
10
+ <template>
11
+ <Story title="Textarea">
12
+ <Variant title="Default">
13
+ <Textarea v-model="basic" placeholder="Placeholder" />
14
+ <template #controls>
15
+ <div class="text-xs text-fg-2 p-2">{{ basic.length }} chars</div>
16
+ </template>
17
+ </Variant>
18
+ <Variant title="Auto Grow (empty)">
19
+ <Textarea v-model="growing" auto-grow placeholder="Start typing, I grow..." />
20
+ </Variant>
21
+ <Variant title="Auto Grow (prefilled)">
22
+ <Textarea v-model="prefilled" auto-grow />
23
+ </Variant>
24
+ <Variant title="Fixed Rows">
25
+ <Textarea v-model="basic" :rows="6" placeholder="6 rows tall..." />
26
+ </Variant>
27
+ </Story>
28
+ </template>
@@ -0,0 +1,28 @@
1
+ <script setup>
2
+ import { toast } from "../src/composables/toast.js"
3
+ import ToastContainer from "../src/components/ToastContainer.vue"
4
+ import Button from "../src/components/Button.vue"
5
+ </script>
6
+
7
+ <template>
8
+ <Story title="Toast">
9
+ <Variant title="All Variants">
10
+ <ToastContainer />
11
+ <div class="flex flex-wrap gap-2">
12
+ <Button @click="toast('Something happened')">Neutral</Button>
13
+ <Button variant="primary" @click="toast.success('Changes saved')">Success</Button>
14
+ <Button @click="toast.warning('Careful with that')">Warning</Button>
15
+ <Button variant="danger" @click="toast.error('Something broke')">Error</Button>
16
+ <Button variant="outline" @click="toast.info('New version available')">Info</Button>
17
+ </div>
18
+ </Variant>
19
+ <Variant title="Long Duration">
20
+ <ToastContainer />
21
+ <Button @click="toast('This stays for 10 seconds', { duration: 10000 })">Long Toast</Button>
22
+ </Variant>
23
+ <Variant title="Persistent">
24
+ <ToastContainer />
25
+ <Button @click="toast.error('Connection lost. Click X to dismiss.', { duration: 0 })">Persistent</Button>
26
+ </Variant>
27
+ </Story>
28
+ </template>
@@ -0,0 +1,57 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import { logEvent } from "histoire/client"
4
+ import ToggleButtons from "../src/components/ToggleButtons.vue"
5
+
6
+ const axes = ref(["x", "y"])
7
+ const formats = ref(["bold"])
8
+ const layers = ref([])
9
+
10
+ function handleUpdate(name, value) {
11
+ logEvent("update:modelValue", { name, value })
12
+ }
13
+ </script>
14
+
15
+ <template>
16
+ <Story title="ToggleButtons">
17
+ <Variant title="Axes (with label)">
18
+ <ToggleButtons
19
+ v-model="axes"
20
+ label="Axes"
21
+ :options="['X', 'Y', 'Z']"
22
+ @update:model-value="v => handleUpdate('axes', v)"
23
+ />
24
+ <template #controls>
25
+ <div class="text-xs text-fg-2 p-2">selected: {{ axes.join(', ') || 'none' }}</div>
26
+ </template>
27
+ </Variant>
28
+ <Variant title="Text Formatting">
29
+ <ToggleButtons
30
+ v-model="formats"
31
+ :options="[
32
+ { value: 'bold', icon: 'material-symbols:format-bold' },
33
+ { value: 'italic', icon: 'material-symbols:format-italic' },
34
+ { value: 'underline', icon: 'material-symbols:format-underlined' },
35
+ { value: 'strike', icon: 'material-symbols:strikethrough-s' }
36
+ ]"
37
+ @update:model-value="v => handleUpdate('formats', v)"
38
+ />
39
+ <template #controls>
40
+ <div class="text-xs text-fg-2 p-2">selected: {{ formats.join(', ') || 'none' }}</div>
41
+ </template>
42
+ </Variant>
43
+ <Variant title="Layers (none selected)">
44
+ <ToggleButtons
45
+ v-model="layers"
46
+ label="Layers"
47
+ :options="[
48
+ { value: 'bg', label: 'BG' },
49
+ { value: 'fg', label: 'FG' },
50
+ { value: 'ui', label: 'UI' },
51
+ { value: 'fx', label: 'FX' }
52
+ ]"
53
+ @update:model-value="v => handleUpdate('layers', v)"
54
+ />
55
+ </Variant>
56
+ </Story>
57
+ </template>
@@ -0,0 +1,34 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import ToggleGroup from "../src/components/ToggleGroup.vue"
4
+
5
+ const view = ref("grid")
6
+ const align = ref("left")
7
+ </script>
8
+
9
+ <template>
10
+ <Story title="ToggleGroup">
11
+ <Variant title="View Switcher">
12
+ <ToggleGroup
13
+ v-model="view"
14
+ :options="[
15
+ { value: 'grid', icon: 'material-symbols:grid-view' },
16
+ { value: 'list', icon: 'material-symbols:view-list' }
17
+ ]"
18
+ />
19
+ <template #controls>
20
+ <div class="text-xs text-fg-2 p-2">view: {{ view }}</div>
21
+ </template>
22
+ </Variant>
23
+ <Variant title="Text Alignment">
24
+ <ToggleGroup
25
+ v-model="align"
26
+ :options="[
27
+ { value: 'left', icon: 'material-symbols:format-align-left' },
28
+ { value: 'center', icon: 'material-symbols:format-align-center' },
29
+ { value: 'right', icon: 'material-symbols:format-align-right' }
30
+ ]"
31
+ />
32
+ </Variant>
33
+ </Story>
34
+ </template>
@@ -0,0 +1,55 @@
1
+ <script setup>
2
+ import { Icon } from "@iconify/vue"
3
+ import Tooltip from "../src/components/Tooltip.vue"
4
+ import Button from "../src/components/Button.vue"
5
+ </script>
6
+
7
+ <template>
8
+ <Story title="Tooltip">
9
+ <Variant title="Basic">
10
+ <div class="flex items-center gap-4 p-8">
11
+ <Tooltip text="Edit this item">
12
+ <Button variant="icon"><Icon icon="material-symbols:edit-outline" class="text-base" /></Button>
13
+ </Tooltip>
14
+ <Tooltip text="Delete permanently">
15
+ <Button variant="icon"><Icon icon="material-symbols:delete-outline" class="text-base" /></Button>
16
+ </Tooltip>
17
+ <Tooltip text="Copy to clipboard">
18
+ <Button variant="icon"><Icon icon="material-symbols:content-copy" class="text-base" /></Button>
19
+ </Tooltip>
20
+ </div>
21
+ </Variant>
22
+ <Variant title="Placements">
23
+ <div class="flex items-center justify-center gap-6 p-16">
24
+ <Tooltip text="Top (default)" placement="top">
25
+ <Button>Top</Button>
26
+ </Tooltip>
27
+ <Tooltip text="Bottom tooltip" placement="bottom">
28
+ <Button>Bottom</Button>
29
+ </Tooltip>
30
+ <Tooltip text="Left tooltip" placement="left">
31
+ <Button>Left</Button>
32
+ </Tooltip>
33
+ <Tooltip text="Right tooltip" placement="right">
34
+ <Button>Right</Button>
35
+ </Tooltip>
36
+ </div>
37
+ </Variant>
38
+ <Variant title="No Delay">
39
+ <div class="p-8">
40
+ <Tooltip text="Instant tooltip" :delay="0">
41
+ <Button>Hover me (no delay)</Button>
42
+ </Tooltip>
43
+ </div>
44
+ </Variant>
45
+ <Variant title="On Text">
46
+ <div class="p-8 flex items-center gap-1">
47
+ <span class="text-base text-fg-1">Hover the</span>
48
+ <Tooltip text="This is an explanation">
49
+ <span class="text-base text-accent cursor-default underline decoration-dotted underline-offset-2">underlined text</span>
50
+ </Tooltip>
51
+ <span class="text-base text-fg-1">for more info</span>
52
+ </div>
53
+ </Variant>
54
+ </Story>
55
+ </template>
@@ -0,0 +1,115 @@
1
+ <script setup>
2
+ import { ref } from "vue"
3
+ import Tree from "../src/components/Tree.vue"
4
+
5
+ const selected = ref(null)
6
+ const filterSelected = ref(null)
7
+
8
+ const fileTree = [
9
+ {
10
+ key: "src",
11
+ label: "src",
12
+ icon: "material-symbols:folder-outline",
13
+ children: [
14
+ {
15
+ key: "src/components",
16
+ label: "components",
17
+ icon: "material-symbols:folder-outline",
18
+ children: [
19
+ { key: "src/components/Button.vue", label: "Button.vue", icon: "material-symbols:description-outline" },
20
+ { key: "src/components/Input.vue", label: "Input.vue", icon: "material-symbols:description-outline" },
21
+ { key: "src/components/Select.vue", label: "Select.vue", icon: "material-symbols:description-outline" },
22
+ { key: "src/components/Modal.vue", label: "Modal.vue", icon: "material-symbols:description-outline" }
23
+ ]
24
+ },
25
+ {
26
+ key: "src/composables",
27
+ label: "composables",
28
+ icon: "material-symbols:folder-outline",
29
+ children: [
30
+ { key: "src/composables/useClickOutside.js", label: "useClickOutside.js", icon: "material-symbols:description-outline" },
31
+ { key: "src/composables/usePointerDrag.js", label: "usePointerDrag.js", icon: "material-symbols:description-outline" }
32
+ ]
33
+ },
34
+ { key: "src/index.js", label: "index.js", icon: "material-symbols:description-outline" },
35
+ { key: "src/style.css", label: "style.css", icon: "material-symbols:description-outline" }
36
+ ]
37
+ },
38
+ {
39
+ key: "stories",
40
+ label: "stories",
41
+ icon: "material-symbols:folder-outline",
42
+ children: [
43
+ { key: "stories/Button.story.vue", label: "Button.story.vue", icon: "material-symbols:description-outline" },
44
+ { key: "stories/Input.story.vue", label: "Input.story.vue", icon: "material-symbols:description-outline" },
45
+ { key: "stories/Overview.story.vue", label: "Overview.story.vue", icon: "material-symbols:description-outline" }
46
+ ]
47
+ },
48
+ { key: "package.json", label: "package.json", icon: "material-symbols:settings-outline" },
49
+ { key: "tailwind.config.js", label: "tailwind.config.js", icon: "material-symbols:settings-outline" },
50
+ { key: "README.md", label: "README.md", icon: "material-symbols:description-outline" }
51
+ ]
52
+ </script>
53
+
54
+ <template>
55
+ <Story title="Tree">
56
+ <Variant title="Basic">
57
+ <div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
58
+ <Tree
59
+ v-model="selected"
60
+ :items="fileTree"
61
+ :default-expanded="['src', 'src/components']"
62
+ />
63
+ </div>
64
+ <template #controls>
65
+ <div class="text-xs text-fg-2 p-2">selected: {{ selected ?? 'null' }}</div>
66
+ </template>
67
+ </Variant>
68
+ <Variant title="All Expanded">
69
+ <div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
70
+ <Tree
71
+ v-model="selected"
72
+ :items="fileTree"
73
+ :default-expanded="true"
74
+ />
75
+ </div>
76
+ </Variant>
77
+ <Variant title="With Filter">
78
+ <div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
79
+ <Tree
80
+ v-model="filterSelected"
81
+ :items="fileTree"
82
+ filterable
83
+ filter-placeholder="find file..."
84
+ :default-expanded="['src']"
85
+ />
86
+ </div>
87
+ <template #controls>
88
+ <div class="text-xs text-fg-2 p-2">selected: {{ filterSelected ?? 'null' }}</div>
89
+ </template>
90
+ </Variant>
91
+ <Variant title="No Icons">
92
+ <div class="w-64 h-80 border border-line rounded-sm overflow-hidden">
93
+ <Tree
94
+ v-model="selected"
95
+ :items="[
96
+ { key: 'a', label: 'Animals', children: [
97
+ { key: 'a1', label: 'Cat' },
98
+ { key: 'a2', label: 'Dog' },
99
+ { key: 'a3', label: 'Fish', children: [
100
+ { key: 'a3a', label: 'Goldfish' },
101
+ { key: 'a3b', label: 'Salmon' }
102
+ ]}
103
+ ]},
104
+ { key: 'b', label: 'Plants', children: [
105
+ { key: 'b1', label: 'Oak' },
106
+ { key: 'b2', label: 'Pine' }
107
+ ]},
108
+ { key: 'c', label: 'Minerals' }
109
+ ]"
110
+ :default-expanded="['a']"
111
+ />
112
+ </div>
113
+ </Variant>
114
+ </Story>
115
+ </template>
@@ -0,0 +1,9 @@
1
+ import preset from "./tailwind.preset.js"
2
+
3
+ export default {
4
+ presets: [preset],
5
+ content: [
6
+ "./src/**/*.{vue,js}",
7
+ "./stories/**/*.{vue,js}"
8
+ ]
9
+ }