@histoire/controls 0.1.5 → 0.2.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.
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'HstWrapper',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { VTooltip as vTooltip } from 'floating-vue'
9
+
10
+ const props = defineProps<{
11
+ title?: string
12
+ }>()
13
+ </script>
14
+
15
+ <template>
16
+ <label class="htw-p-2 hover:htw-bg-primary-100 dark:hover:htw-bg-primary-800 htw-flex htw-gap-2 htw-flex-wrap">
17
+ <span
18
+ v-tooltip="{
19
+ content: title,
20
+ placement: 'left',
21
+ distance: 12,
22
+ }"
23
+ class="htw-w-28 htw-whitespace-nowrap htw-text-ellipsis htw-overflow-hidden htw-shrink-0"
24
+ >
25
+ {{ title }}
26
+ </span>
27
+ <span class="htw-block htw-grow">
28
+ <slot />
29
+ </span>
30
+ </label>
31
+ </template>
@@ -17,17 +17,15 @@ function initState () {
17
17
  <template #default="{ state }">
18
18
  <HstCheckbox
19
19
  v-model="state.checked"
20
- >
21
- Label
22
- </HstCheckbox>
20
+ title="Label"
21
+ />
23
22
  </template>
24
23
 
25
24
  <template #controls="{ state }">
26
25
  <HstCheckbox
27
26
  v-model="state.checked"
28
- >
29
- Label
30
- </HstCheckbox>
27
+ title="Label"
28
+ />
31
29
  </template>
32
30
  </Variant>
33
31
  </Story>
@@ -6,9 +6,7 @@ describe('HstCheckbox', () => {
6
6
  const wrapper = mount(HstCheckbox, {
7
7
  props: {
8
8
  modelValue: false,
9
- },
10
- slots: {
11
- default: 'Label',
9
+ title: 'Label',
12
10
  },
13
11
  })
14
12
  await wrapper.trigger('click')
@@ -20,9 +18,7 @@ describe('HstCheckbox', () => {
20
18
  const wrapper = mount(HstCheckbox, {
21
19
  props: {
22
20
  modelValue: true,
23
- },
24
- slots: {
25
- default: 'Label',
21
+ title: 'Label',
26
22
  },
27
23
  })
28
24
  await wrapper.trigger('click')
@@ -6,13 +6,12 @@ export default {
6
6
 
7
7
  <script lang="ts" setup>
8
8
  import { computed, ref, watch } from 'vue'
9
+ import HstWrapper from '../HstWrapper.vue'
9
10
 
10
- const props = defineProps({
11
- modelValue: {
12
- type: Boolean,
13
- default: false,
14
- },
15
- })
11
+ const props = defineProps<{
12
+ modelValue: boolean
13
+ title?: string
14
+ }>()
16
15
 
17
16
  const emit = defineEmits({
18
17
  'update:modelValue': (newValue: boolean) => true,
@@ -37,21 +36,22 @@ watch(path, value => {
37
36
  </script>
38
37
 
39
38
  <template>
40
- <div
39
+ <HstWrapper
41
40
  role="checkbox"
42
41
  tabindex="0"
43
- class="htw-flex htw-items-center htw-gap-2 htw-select-none htw-px-4 htw-py-3 htw-cursor-pointer hover:htw-bg-primary-100 dark:hover:htw-bg-primary-700"
42
+ class="htw-cursor-pointer htw-items-center"
43
+ :title="title"
44
44
  @click="toggle()"
45
45
  @keydown.enter.prevent="toggle()"
46
46
  @keydown.space.prevent="toggle()"
47
47
  >
48
48
  <div class="htw-text-white htw-w-[16px] htw-h-[16px] htw-relative">
49
49
  <div
50
- class="htw-border group-active:htw-bg-gray-500/20 htw-rounded-sm htw-box-border htw-absolute htw-inset-0 htw-transition-border htw-duration-150 htw-ease-out"
50
+ class="htw-border htw-border-solid group-active:htw-bg-gray-500/20 htw-rounded-sm htw-box-border htw-absolute htw-inset-0 htw-transition-border htw-duration-150 htw-ease-out"
51
51
  :class="[
52
52
  modelValue
53
53
  ? 'htw-border-primary-500 htw-border-8'
54
- : 'htw-border-gray-300 dark:htw-border-gray-500 htw-delay-150',
54
+ : 'htw-border-black/25 dark:htw-border-white/25 htw-delay-150',
55
55
  ]"
56
56
  />
57
57
  <svg
@@ -76,7 +76,5 @@ watch(path, value => {
76
76
  />
77
77
  </svg>
78
78
  </div>
79
-
80
- <slot />
81
- </div>
79
+ </HstWrapper>
82
80
  </template>
@@ -1,59 +1,67 @@
1
1
  // Peeky snapshots v1.0
2
2
 
3
3
  exports[`HstCheckbox toggle to checked 1`] = `
4
- <div
4
+ <label
5
+ class="htw-p-2 hover:htw-bg-primary-100 dark:hover:htw-bg-primary-800 htw-flex htw-gap-2 htw-flex-wrap htw-cursor-pointer htw-items-center"
5
6
  role="checkbox"
6
7
  tabindex="0"
7
- class="htw-flex htw-items-center htw-gap-2 htw-select-none htw-px-4 htw-py-3 htw-cursor-pointer hover:htw-bg-primary-100 dark:hover:htw-bg-primary-700"
8
8
  >
9
- <div class="htw-text-white htw-w-[16px] htw-h-[16px] htw-relative">
10
- <div class="htw-border group-active:htw-bg-gray-500/20 htw-rounded-sm htw-box-border htw-absolute htw-inset-0 htw-transition-border htw-duration-150 htw-ease-out htw-border-gray-300 dark:htw-border-gray-500 htw-delay-150">
11
- </div>
12
- <svg
13
- width="16"
14
- height="16"
15
- viewbox="0 0 24 24"
16
- class="htw-relative htw-z-10"
17
- >
18
- <path
19
- d="m 4 12 l 5 5 l 10 -10"
20
- fill="none"
21
- class="htw-stroke-white htw-stroke-2 htw-duration-200 htw-ease-in-out htw-transition-all"
22
- stroke-dasharray="21.21"
23
- stroke-dashoffset="21.21"
9
+ <span class="htw-w-28 htw-whitespace-nowrap htw-text-ellipsis htw-overflow-hidden htw-shrink-0 v-popper--has-tooltip">
10
+ Label
11
+ </span>
12
+ <span class="htw-block htw-grow">
13
+ <div class="htw-text-white htw-w-[16px] htw-h-[16px] htw-relative">
14
+ <div class="htw-border htw-border-solid group-active:htw-bg-gray-500/20 htw-rounded-sm htw-box-border htw-absolute htw-inset-0 htw-transition-border htw-duration-150 htw-ease-out htw-border-black/25 dark:htw-border-white/25 htw-delay-150">
15
+ </div>
16
+ <svg
17
+ width="16"
18
+ height="16"
19
+ viewbox="0 0 24 24"
20
+ class="htw-relative htw-z-10"
24
21
  >
25
- </path>
26
- </svg>
27
- </div>
28
- Label
29
- </div>
22
+ <path
23
+ d="m 4 12 l 5 5 l 10 -10"
24
+ fill="none"
25
+ class="htw-stroke-white htw-stroke-2 htw-duration-200 htw-ease-in-out htw-transition-all"
26
+ stroke-dasharray="21.21"
27
+ stroke-dashoffset="21.21"
28
+ >
29
+ </path>
30
+ </svg>
31
+ </div>
32
+ </span>
33
+ </label>
30
34
  `;
31
35
 
32
36
  exports[`HstCheckbox toggle to unchecked 1`] = `
33
- <div
37
+ <label
38
+ class="htw-p-2 hover:htw-bg-primary-100 dark:hover:htw-bg-primary-800 htw-flex htw-gap-2 htw-flex-wrap htw-cursor-pointer htw-items-center"
34
39
  role="checkbox"
35
40
  tabindex="0"
36
- class="htw-flex htw-items-center htw-gap-2 htw-select-none htw-px-4 htw-py-3 htw-cursor-pointer hover:htw-bg-primary-100 dark:hover:htw-bg-primary-700"
37
41
  >
38
- <div class="htw-text-white htw-w-[16px] htw-h-[16px] htw-relative">
39
- <div class="htw-border group-active:htw-bg-gray-500/20 htw-rounded-sm htw-box-border htw-absolute htw-inset-0 htw-transition-border htw-duration-150 htw-ease-out htw-border-primary-500 htw-border-8">
40
- </div>
41
- <svg
42
- width="16"
43
- height="16"
44
- viewbox="0 0 24 24"
45
- class="htw-relative htw-z-10"
46
- >
47
- <path
48
- d="m 4 12 l 5 5 l 10 -10"
49
- fill="none"
50
- class="htw-stroke-white htw-stroke-2 htw-duration-200 htw-ease-in-out htw-transition-all htw-delay-150"
51
- stroke-dasharray="21.21"
52
- stroke-dashoffset="0"
42
+ <span class="htw-w-28 htw-whitespace-nowrap htw-text-ellipsis htw-overflow-hidden htw-shrink-0 v-popper--has-tooltip">
43
+ Label
44
+ </span>
45
+ <span class="htw-block htw-grow">
46
+ <div class="htw-text-white htw-w-[16px] htw-h-[16px] htw-relative">
47
+ <div class="htw-border htw-border-solid group-active:htw-bg-gray-500/20 htw-rounded-sm htw-box-border htw-absolute htw-inset-0 htw-transition-border htw-duration-150 htw-ease-out htw-border-primary-500 htw-border-8">
48
+ </div>
49
+ <svg
50
+ width="16"
51
+ height="16"
52
+ viewbox="0 0 24 24"
53
+ class="htw-relative htw-z-10"
53
54
  >
54
- </path>
55
- </svg>
56
- </div>
57
- Label
58
- </div>
55
+ <path
56
+ d="m 4 12 l 5 5 l 10 -10"
57
+ fill="none"
58
+ class="htw-stroke-white htw-stroke-2 htw-duration-200 htw-ease-in-out htw-transition-all htw-delay-150"
59
+ stroke-dasharray="21.21"
60
+ stroke-dashoffset="0"
61
+ >
62
+ </path>
63
+ </svg>
64
+ </div>
65
+ </span>
66
+ </label>
59
67
  `;
@@ -0,0 +1,41 @@
1
+ <script lang="ts" setup>
2
+ import HstNumber from './HstNumber.vue'
3
+
4
+ function initState () {
5
+ return {
6
+ count: 20,
7
+ step: 1,
8
+ }
9
+ }
10
+ </script>
11
+
12
+ <template>
13
+ <Story
14
+ title="HstNumber"
15
+ >
16
+ <Variant
17
+ title="default"
18
+ :init-state="initState"
19
+ >
20
+ <template #default="{ state }">
21
+ <HstNumber
22
+ v-model="state.count"
23
+ :step="state.step"
24
+ title="Count"
25
+ />
26
+ </template>
27
+
28
+ <template #controls="{ state }">
29
+ <HstNumber
30
+ v-model="state.count"
31
+ title="Count"
32
+ />
33
+
34
+ <HstNumber
35
+ v-model="state.step"
36
+ title="Step"
37
+ />
38
+ </template>
39
+ </Variant>
40
+ </Story>
41
+ </template>
@@ -0,0 +1,92 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'HstNumber',
4
+
5
+ inheritAttrs: false,
6
+ }
7
+ </script>
8
+
9
+ <script lang="ts" setup>
10
+ import { computed, ref, onUnmounted } from 'vue'
11
+ import HstWrapper from '../HstWrapper.vue'
12
+
13
+ const props = defineProps<{
14
+ title?: string
15
+ modelValue: number
16
+ }>()
17
+
18
+ const emit = defineEmits({
19
+ 'update:modelValue': (newValue: number) => true,
20
+ })
21
+
22
+ const numberModel = computed({
23
+ get: () => props.modelValue,
24
+ set: value => {
25
+ emit('update:modelValue', value)
26
+ },
27
+ })
28
+
29
+ const input = ref<HTMLInputElement>()
30
+
31
+ function focusAndSelect () {
32
+ input.value.focus()
33
+ input.value.select()
34
+ }
35
+
36
+ // Drag to modify
37
+
38
+ const isDragging = ref(false)
39
+ let startX: number
40
+ let startValue: number
41
+
42
+ function onMouseDown (event: MouseEvent) {
43
+ isDragging.value = true
44
+ startX = event.clientX
45
+ startValue = numberModel.value
46
+ window.addEventListener('mousemove', onMouseMove)
47
+ window.addEventListener('mouseup', stopDragging)
48
+ }
49
+
50
+ function onMouseMove (event: MouseEvent) {
51
+ let step = parseFloat(input.value.step)
52
+ if (isNaN(step)) {
53
+ step = 1
54
+ }
55
+ numberModel.value = startValue + Math.round((event.clientX - startX) / 10 / step) * step
56
+ }
57
+
58
+ function stopDragging () {
59
+ isDragging.value = false
60
+ window.removeEventListener('mousemove', onMouseMove)
61
+ window.removeEventListener('mouseup', stopDragging)
62
+ }
63
+
64
+ onUnmounted(() => {
65
+ stopDragging()
66
+ })
67
+ </script>
68
+
69
+ <template>
70
+ <HstWrapper
71
+ class="htw-cursor-ew-resize htw-items-center"
72
+ :title="title"
73
+ :class="[
74
+ $attrs.class,
75
+ { 'htw-select-none': isDragging },
76
+ ]"
77
+ :style="$attrs.style"
78
+ @click="focusAndSelect"
79
+ @mousedown="onMouseDown"
80
+ >
81
+ <input
82
+ ref="input"
83
+ v-bind="{ ...$attrs, class: null, style: null }"
84
+ v-model.number="numberModel"
85
+ type="number"
86
+ :class="{
87
+ 'htw-select-none': isDragging,
88
+ }"
89
+ class="htw-text-inherit htw-bg-transparent htw-w-full htw-outline-none htw-pl-2 htw-py-1 -htw-my-1 htw-border htw-border-solid htw-border-black/25 dark:htw-border-white/25 focus:htw-border-primary-500 dark:focus:htw-border-primary-500 htw-rounded-sm htw-cursor-ew-resize"
90
+ >
91
+ </HstWrapper>
92
+ </template>
@@ -1,33 +1,42 @@
1
1
  <script lang="ts" setup>
2
- import HstInput from './HstInput.vue'
2
+ import HstText from './HstText.vue'
3
3
 
4
4
  function initState () {
5
5
  return {
6
+ label: 'My really long label',
6
7
  text: '',
7
8
  }
8
9
  }
9
10
  </script>
10
11
 
11
12
  <template>
12
- <Story title="HstInput">
13
+ <Story
14
+ title="HstText"
15
+ :layout="{
16
+ type: 'grid',
17
+ width: '100%',
18
+ }"
19
+ >
13
20
  <Variant
14
- title="playground"
21
+ title="default"
15
22
  :init-state="initState"
16
23
  >
17
24
  <template #default="{ state }">
18
- <HstInput
25
+ <HstText
19
26
  v-model="state.text"
20
- >
21
- Label
22
- </HstInput>
27
+ :title="state.label"
28
+ />
23
29
  </template>
24
30
 
25
31
  <template #controls="{ state }">
26
- <HstInput
32
+ <HstText
33
+ v-model="state.label"
34
+ title="Label"
35
+ />
36
+ <HstText
27
37
  v-model="state.text"
28
- >
29
- Label
30
- </HstInput>
38
+ title="Text"
39
+ />
31
40
  </template>
32
41
  </Variant>
33
42
 
@@ -36,18 +45,17 @@ function initState () {
36
45
  :init-state="initState"
37
46
  >
38
47
  <template #default="{ state }">
39
- <HstInput
48
+ <HstText
40
49
  v-model="state.text"
41
50
  placeholder="Enter some text..."
42
51
  />
43
52
  </template>
44
53
 
45
54
  <template #controls="{ state }">
46
- <HstInput
55
+ <HstText
47
56
  v-model="state.text"
48
- >
49
- Label
50
- </HstInput>
57
+ title="Text"
58
+ />
51
59
  </template>
52
60
  </Variant>
53
61
  </Story>
@@ -0,0 +1,40 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'HstText',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { ref } from 'vue'
9
+ import HstWrapper from '../HstWrapper.vue'
10
+
11
+ const props = defineProps<{
12
+ title?: string
13
+ modelValue: string
14
+ }>()
15
+
16
+ const emit = defineEmits({
17
+ 'update:modelValue': (newValue: string) => true,
18
+ })
19
+
20
+ const input = ref<HTMLInputElement>()
21
+ </script>
22
+
23
+ <template>
24
+ <HstWrapper
25
+ :title="title"
26
+ class="htw-cursor-text htw-items-center"
27
+ :class="$attrs.class"
28
+ :style="$attrs.style"
29
+ @click="input.focus()"
30
+ >
31
+ <input
32
+ ref="input"
33
+ v-bind="{ ...$attrs, class: null, style: null }"
34
+ type="text"
35
+ :value="modelValue"
36
+ class="htw-text-inherit htw-bg-transparent htw-w-full htw-outline-none htw-px-2 htw-py-1 -htw-my-1 htw-border htw-border-solid htw-border-black/25 dark:htw-border-white/25 focus:htw-border-primary-500 dark:focus:htw-border-primary-500 htw-rounded-sm"
37
+ @input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
38
+ >
39
+ </HstWrapper>
40
+ </template>
@@ -0,0 +1,32 @@
1
+ <script lang="ts" setup>
2
+ import HstTextarea from './HstTextarea.vue'
3
+
4
+ function initState () {
5
+ return {
6
+ text: '',
7
+ }
8
+ }
9
+ </script>
10
+
11
+ <template>
12
+ <Story title="HstTextarea">
13
+ <Variant
14
+ title="default"
15
+ :init-state="initState"
16
+ >
17
+ <template #default="{ state }">
18
+ <HstTextarea
19
+ v-model="state.text"
20
+ title="Textarea"
21
+ />
22
+ </template>
23
+
24
+ <template #controls="{ state }">
25
+ <HstTextarea
26
+ v-model="state.text"
27
+ title="Text"
28
+ />
29
+ </template>
30
+ </Variant>
31
+ </Story>
32
+ </template>
@@ -0,0 +1,40 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'HstTextarea',
4
+ inheritAttrs: false,
5
+ }
6
+ </script>
7
+
8
+ <script lang="ts" setup>
9
+ import { ref } from 'vue'
10
+ import HstWrapper from '../HstWrapper.vue'
11
+
12
+ const props = defineProps<{
13
+ title?: string
14
+ modelValue: string
15
+ }>()
16
+
17
+ const emit = defineEmits({
18
+ 'update:modelValue': (newValue: string) => true,
19
+ })
20
+
21
+ const input = ref<HTMLInputElement>()
22
+ </script>
23
+
24
+ <template>
25
+ <HstWrapper
26
+ :title="title"
27
+ class="htw-cursor-text"
28
+ :class="$attrs.class"
29
+ :style="$attrs.style"
30
+ @click="input.focus()"
31
+ >
32
+ <textarea
33
+ ref="input"
34
+ v-bind="{ ...$attrs, class: null, style: null }"
35
+ :value="modelValue"
36
+ class="htw-text-inherit htw-bg-transparent htw-w-full htw-outline-none htw-px-2 htw-py-1 -htw-my-1 htw-border htw-border-solid htw-border-black/25 dark:htw-border-white/25 focus:htw-border-primary-500 dark:focus:htw-border-primary-500 htw-rounded-sm htw-box-border htw-resize-y htw-min-h-[26px]"
37
+ @input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
38
+ />
39
+ </HstWrapper>
40
+ </template>
package/src/index.ts CHANGED
@@ -1,11 +1,17 @@
1
1
  import type { App } from 'vue'
2
2
  import HstCheckboxVue from './components/checkbox/HstCheckbox.vue'
3
- import HstInputVue from './components/input/HstInput.vue'
3
+ import HstTextVue from './components/text/HstText.vue'
4
+ import HstNumberVue from './components/number/HstNumber.vue'
5
+ import HstTextareaVue from './components/textarea/HstTextarea.vue'
4
6
 
5
7
  export const HstCheckbox = HstCheckboxVue
6
- export const HstInput = HstInputVue
8
+ export const HstText = HstTextVue
9
+ export const HstNumber = HstNumberVue
10
+ export const HstTextarea = HstTextareaVue
7
11
 
8
12
  export function registerVueComponents (app: App) {
9
13
  app.component('HstCheckbox', HstCheckboxVue)
10
- app.component('HstInput', HstInputVue)
14
+ app.component('HstText', HstTextVue)
15
+ app.component('HstNumber', HstNumberVue)
16
+ app.component('HstTextarea', HstTextareaVue)
11
17
  }
@@ -1,7 +1,17 @@
1
+ @import 'floating-vue/dist/style.css';
2
+
1
3
  @tailwind base;
2
4
  @tailwind components;
3
5
  @tailwind utilities;
4
6
 
7
+
5
8
  body {
9
+ font-size: 18px;
6
10
  @apply dark:htw-text-gray-100;
7
11
  }
12
+
13
+ @media (min-width: 640px) {
14
+ body {
15
+ font-size: 14px;
16
+ }
17
+ }
@@ -1,18 +0,0 @@
1
- declare const _default: import("vue").DefineComponent<{
2
- modelValue: {
3
- type: (StringConstructor | NumberConstructor)[];
4
- default: string;
5
- };
6
- }, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
7
- 'update:modelValue': (newValue: string | number) => true;
8
- }, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
9
- modelValue: {
10
- type: (StringConstructor | NumberConstructor)[];
11
- default: string;
12
- };
13
- }>> & {
14
- "onUpdate:modelValue"?: (newValue: string | number) => any;
15
- }, {
16
- modelValue: string | number;
17
- }>;
18
- export default _default;
@@ -1,47 +0,0 @@
1
- <script lang="ts">
2
- export default {
3
- name: 'HstInput',
4
-
5
- inheritAttrs: false,
6
- }
7
- </script>
8
-
9
- <script lang="ts" setup>
10
- import { ref } from 'vue'
11
-
12
- const props = defineProps({
13
- modelValue: {
14
- type: [String, Number],
15
- default: '',
16
- },
17
- })
18
-
19
- const emit = defineEmits({
20
- 'update:modelValue': (newValue: string | number) => true,
21
- })
22
-
23
- const input = ref<HTMLInputElement>()
24
- </script>
25
-
26
- <template>
27
- <div
28
- class="htw-p-2 hover:htw-bg-primary-100 dark:hover:htw-bg-primary-700 htw-cursor-text"
29
- :class="$attrs.class"
30
- :style="$attrs.style"
31
- @click="input.focus()"
32
- >
33
- <label
34
- v-if="$slots.default"
35
- class="htw-text-sm htw-px-2 htw-cursor-text"
36
- >
37
- <slot />
38
- </label>
39
- <input
40
- ref="input"
41
- v-bind="{ ...$attrs, style: null, class: null }"
42
- :value="modelValue"
43
- class="htw-text-inherit htw-bg-transparent htw-w-full htw-outline-none htw-px-2 htw-py-0 htw-border htw-border-gray-300 dark:htw-border-gray-500 focus:htw-border-primary-500 dark:focus:htw-border-primary-500 htw-rounded-sm"
44
- @input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
45
- >
46
- </div>
47
- </template>