@histoire/controls 0.2.5 → 0.3.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.
@@ -5,14 +5,12 @@ export default {
5
5
  </script>
6
6
 
7
7
  <script lang="ts" setup>
8
- import { computed } from 'vue'
8
+ import { computed, ref } from 'vue'
9
9
  import { VTooltip as vTooltip } from 'floating-vue'
10
10
  import HstCopyIcon from '../HstCopyIcon.vue'
11
11
 
12
12
  const props = defineProps<{
13
13
  shades: Record<string, string>
14
- // @TODO report eslint bug
15
- // eslint-disable-next-line func-call-spacing
16
14
  getName?: (key: string, color: string) => string
17
15
  search?: string
18
16
  }>()
@@ -38,6 +36,8 @@ const displayedShades = computed(() => {
38
36
  }
39
37
  return list
40
38
  })
39
+
40
+ const hover = ref<string>(null)
41
41
  </script>
42
42
 
43
43
  <template>
@@ -48,7 +48,9 @@ const displayedShades = computed(() => {
48
48
  <div
49
49
  v-for="shade of displayedShades"
50
50
  :key="shade.key"
51
- class="htw-flex htw-flex-col htw-gap-2 htw-group"
51
+ class="htw-flex htw-flex-col htw-gap-2"
52
+ @mouseenter="hover = shade.key"
53
+ @mouseleave="hover = null"
52
54
  >
53
55
  <slot
54
56
  :color="shade.color"
@@ -67,8 +69,9 @@ const displayedShades = computed(() => {
67
69
  class="htw-my-0 htw-truncate htw-shrink"
68
70
  >{{ shade.name }}</pre>
69
71
  <HstCopyIcon
72
+ v-if="hover === shade.key"
70
73
  :content="shade.name"
71
- class="htw-hidden group-hover:htw-block htw-flex-none"
74
+ class="htw-flex-none"
72
75
  />
73
76
  </div>
74
77
  <div class="htw-flex htw-gap-1">
@@ -77,8 +80,9 @@ const displayedShades = computed(() => {
77
80
  class="htw-my-0 htw-opacity-50 htw-truncate htw-shrink"
78
81
  >{{ shade.color }}</pre>
79
82
  <HstCopyIcon
83
+ v-if="hover === shade.key"
80
84
  :content="shade.color"
81
- class="htw-hidden group-hover:htw-block htw-flex-none"
85
+ class="htw-flex-none"
82
86
  />
83
87
  </div>
84
88
  </div>
@@ -1,20 +1,18 @@
1
1
  <script lang="ts">
2
2
  export default {
3
- name: 'HstDesignTokens',
3
+ name: 'HstTokenGrid',
4
4
  }
5
5
  </script>
6
6
 
7
7
  <script lang="ts" setup>
8
- import { computed, withDefaults } from 'vue'
8
+ import { computed, ref, withDefaults } from 'vue'
9
9
  import { VTooltip as vTooltip } from 'floating-vue'
10
10
  import HstCopyIcon from '../HstCopyIcon.vue'
11
11
 
12
12
  const props = withDefaults(defineProps<{
13
- tokens: Record<string, string | number>
13
+ tokens: Record<string, string | number | any[] | Record<string, any>>
14
14
  colSize?: number
15
- // @TODO report eslint bug
16
- // eslint-disable-next-line func-call-spacing
17
- getName?: (key: string, value: string | number) => string
15
+ getName?: (key: string, value: string | number | any[] | Record<string, any>) => string
18
16
  }>(), {
19
17
  colSize: 180,
20
18
  getName: null,
@@ -28,20 +26,29 @@ const processedTokens = computed(() => {
28
26
  return {
29
27
  key,
30
28
  name,
31
- value: typeof value === 'string' ? value : value.toString(),
29
+ value: typeof value === 'number' ? value.toString() : value,
32
30
  }
33
31
  })
34
32
  })
35
33
 
36
34
  const colSizePx = computed(() => `${props.colSize}px`)
35
+
36
+ const hover = ref<string>(null)
37
37
  </script>
38
38
 
39
39
  <template>
40
- <div class="htw-bind-col-size htw-grid htw-gap-4 htw-m-4">
40
+ <div
41
+ class="htw-bind-col-size htw-grid htw-gap-4 htw-m-4"
42
+ :style="{
43
+ '--histoire-col-size': colSizePx,
44
+ }"
45
+ >
41
46
  <div
42
47
  v-for="token of processedTokens"
43
48
  :key="token.key"
44
- class="htw-flex htw-flex-col htw-gap-2 htw-group"
49
+ class="htw-flex htw-flex-col htw-gap-2"
50
+ @mouseenter="hover = token.key"
51
+ @mouseleave="hover = null"
45
52
  >
46
53
  <slot
47
54
  :token="token"
@@ -53,8 +60,9 @@ const colSizePx = computed(() => `${props.colSize}px`)
53
60
  class="htw-my-0 htw-truncate htw-shrink"
54
61
  >{{ token.name }}</pre>
55
62
  <HstCopyIcon
63
+ v-if="hover === token.key"
56
64
  :content="token.name"
57
- class="htw-hidden group-hover:htw-block htw-flex-none"
65
+ class="htw-flex-none"
58
66
  />
59
67
  </div>
60
68
  <div class="htw-flex htw-gap-1">
@@ -63,8 +71,9 @@ const colSizePx = computed(() => `${props.colSize}px`)
63
71
  class="htw-my-0 htw-opacity-50 htw-truncate htw-shrink"
64
72
  >{{ token.value }}</pre>
65
73
  <HstCopyIcon
66
- :content="token.value"
67
- class="htw-hidden group-hover:htw-block htw-flex-none"
74
+ v-if="hover === token.key"
75
+ :content="typeof token.value === 'string' ? token.value : JSON.stringify(token.value)"
76
+ class="htw-flex-none"
68
77
  />
69
78
  </div>
70
79
  </div>
@@ -72,8 +81,8 @@ const colSizePx = computed(() => `${props.colSize}px`)
72
81
  </div>
73
82
  </template>
74
83
 
75
- <style scoped>
84
+ <style>
76
85
  .htw-bind-col-size {
77
- grid-template-columns: repeat(auto-fill, minmax(v-bind(colSizePx), 1fr));
86
+ grid-template-columns: repeat(auto-fill, minmax(var(--histoire-col-size), 1fr));
78
87
  }
79
88
  </style>
@@ -1,18 +1,16 @@
1
1
  <script lang="ts">
2
2
  export default {
3
- name: 'HstDesignTokens',
3
+ name: 'HstTokenList',
4
4
  }
5
5
  </script>
6
6
 
7
7
  <script lang="ts" setup>
8
- import { computed } from 'vue'
8
+ import { computed, ref } from 'vue'
9
9
  import HstCopyIcon from '../HstCopyIcon.vue'
10
10
 
11
11
  const props = defineProps<{
12
- tokens: Record<string, string | number>
13
- // @TODO report eslint bug
14
- // eslint-disable-next-line func-call-spacing
15
- getName?: (key: string, value: string | number) => string
12
+ tokens: Record<string, string | number | any[] | Record<string, any>>
13
+ getName?: (key: string, value: string | number | any[] | Record<string, any>) => string
16
14
  }>()
17
15
 
18
16
  const processedTokens = computed(() => {
@@ -23,17 +21,21 @@ const processedTokens = computed(() => {
23
21
  return {
24
22
  key,
25
23
  name,
26
- value: typeof value === 'string' ? value : value.toString(),
24
+ value: typeof value === 'number' ? value.toString() : value,
27
25
  }
28
26
  })
29
27
  })
28
+
29
+ const hover = ref<string>(null)
30
30
  </script>
31
31
 
32
32
  <template>
33
33
  <div
34
34
  v-for="token of processedTokens"
35
35
  :key="token.key"
36
- class="htw-flex htw-flex-col htw-gap-2 htw-group htw-my-8"
36
+ class="htw-flex htw-flex-col htw-gap-2 htw-my-8"
37
+ @mouseenter="hover = token.key"
38
+ @mouseleave="hover = null"
37
39
  >
38
40
  <slot
39
41
  :token="token"
@@ -42,15 +44,17 @@ const processedTokens = computed(() => {
42
44
  <div class="htw-flex htw-gap-1">
43
45
  <pre class="htw-my-0 htw-truncate htw-shrink">{{ token.name }}</pre>
44
46
  <HstCopyIcon
47
+ v-if="hover === token.key"
45
48
  :content="token.name"
46
- class="htw-hidden group-hover:htw-block htw-flex-none"
49
+ class="htw-flex-none"
47
50
  />
48
51
  </div>
49
52
  <div class="htw-flex htw-gap-1">
50
53
  <pre class="htw-my-0 htw-opacity-50 htw-truncate htw-shrink">{{ token.value }}</pre>
51
54
  <HstCopyIcon
52
- :content="token.value"
53
- class="htw-hidden group-hover:htw-block htw-flex-none"
55
+ v-if="hover === token.key"
56
+ :content="typeof token.value === 'string' ? token.value : JSON.stringify(token.value)"
57
+ class="htw-flex-none"
54
58
  />
55
59
  </div>
56
60
  </div>
@@ -0,0 +1,110 @@
1
+ <script lang="ts" setup>
2
+ import HstSelect from './HstSelect.vue'
3
+
4
+ const options = [
5
+ { label: 'Crash Bandicoot', value: 'crash-bandicoot' },
6
+ { label: 'The Last of Us', value: 'the-last-of-us' },
7
+ { label: 'Ghost of Tsushima', value: 'ghost-of-tsushima' },
8
+ ]
9
+
10
+ const flatOptions = options.map(option => option.label)
11
+
12
+ function initState () {
13
+ return {
14
+ label: 'My really long label',
15
+ select: 'crash-bandicoot',
16
+ }
17
+ }
18
+ </script>
19
+
20
+ <template>
21
+ <Story
22
+ title="HstSelect"
23
+ :layout="{
24
+ type: 'grid',
25
+ width: '100%',
26
+ }"
27
+ >
28
+ <Variant
29
+ title="default"
30
+ :init-state="initState"
31
+ >
32
+ <template #default="{ state }">
33
+ <HstSelect
34
+ v-model="state.select"
35
+ :title="state.label"
36
+ :options="options"
37
+ />
38
+ </template>
39
+
40
+ <template #controls="{ state }">
41
+ <HstSelect
42
+ v-model="state.select"
43
+ title="Select"
44
+ :options="options"
45
+ />
46
+ </template>
47
+ </Variant>
48
+
49
+ <Variant
50
+ title="no-label"
51
+ :init-state="initState"
52
+ >
53
+ <template #default="{ state }">
54
+ <HstSelect
55
+ v-model="state.select"
56
+ :options="options"
57
+ />
58
+ </template>
59
+ <template #controls="{ state }">
60
+ <HstSelect
61
+ v-model="state.select"
62
+ title="Select"
63
+ :options="options"
64
+ />
65
+ </template>
66
+ </Variant>
67
+
68
+ <Variant
69
+ title="options-as-array-of-objects"
70
+ :init-state="initState"
71
+ >
72
+ <template #default="{ state }">
73
+ <pre class="htw-text-xs htw-bg-gray-50 dark:htw-bg-gray-600 htw-rounded htw-p-4">{{ options }}</pre>
74
+ <HstSelect
75
+ v-model="state.select"
76
+ title="Games"
77
+ :options="options"
78
+ />
79
+ </template>
80
+ <template #controls="{ state }">
81
+ <HstSelect
82
+ v-model="state.select"
83
+ title="Games"
84
+ :options="options"
85
+ />
86
+ </template>
87
+ </Variant>
88
+
89
+ <Variant
90
+ title="options-as-array-of-strings"
91
+ :init-state="initState"
92
+ >
93
+ <template #default="{ state }">
94
+ <pre class="htw-text-xs htw-bg-gray-50 dark:htw-bg-gray-600 htw-rounded htw-p-4">{{ flatOptions }}</pre>
95
+ <HstSelect
96
+ v-model="state.select"
97
+ title="Select"
98
+ :options="flatOptions"
99
+ />
100
+ </template>
101
+ <template #controls="{ state }">
102
+ <HstSelect
103
+ v-model="state.select"
104
+ title="Select"
105
+ :options="flatOptions"
106
+ />
107
+ </template>
108
+ </Variant>
109
+ </Story>
110
+ </template>
@@ -0,0 +1,67 @@
1
+ <script lang="ts">
2
+ export default {
3
+ name: 'HstSelect',
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts" setup>
8
+ import { ref, computed, ComputedRef, PropType } from 'vue'
9
+ import HstWrapper from '../HstWrapper.vue'
10
+
11
+ export interface HstSelectOptions {
12
+ label: string
13
+ value: string
14
+ }
15
+
16
+ const props = defineProps({
17
+ title: {
18
+ type: String,
19
+ default: '',
20
+ },
21
+ modelValue: {
22
+ type: String,
23
+ default: null,
24
+ },
25
+ options: {
26
+ type: Array as PropType<HstSelectOptions[] | string[]>,
27
+ required: true,
28
+ default: () => [],
29
+ },
30
+ })
31
+
32
+ const formattedOtions: ComputedRef<HstSelectOptions[]> =
33
+ computed(() => props.options.map(option => typeof option === 'string' ? { label: option, value: option } as HstSelectOptions : option as HstSelectOptions))
34
+
35
+ const emit = defineEmits({
36
+ 'update:modelValue': (newValue: string) => true,
37
+ })
38
+
39
+ const select = ref<HTMLInputElement>()
40
+ </script>
41
+
42
+ <template>
43
+ <HstWrapper
44
+ :title="title"
45
+ class="htw-cursor-text htw-items-center"
46
+ :class="$attrs.class"
47
+ :style="$attrs.style"
48
+ @click="select.focus()"
49
+ >
50
+ <select
51
+ ref="select"
52
+ 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"
53
+ :value="modelValue"
54
+ @input="emit('update:modelValue', ($event.target as HTMLInputElement).value)"
55
+ >
56
+ <option
57
+ v-for="{ label, value } in formattedOtions"
58
+ v-bind="{ ...$attrs, class: null, style: null }"
59
+ :key="label"
60
+ class="dark:htw-bg-gray-600"
61
+ :value="value"
62
+ >
63
+ {{ label }}
64
+ </option>
65
+ </select>
66
+ </HstWrapper>
67
+ </template>
package/src/index.ts CHANGED
@@ -3,7 +3,10 @@ import HstCheckboxVue from './components/checkbox/HstCheckbox.vue'
3
3
  import HstTextVue from './components/text/HstText.vue'
4
4
  import HstNumberVue from './components/number/HstNumber.vue'
5
5
  import HstTextareaVue from './components/textarea/HstTextarea.vue'
6
+ import HstSelectVue from './components/select/HstSelect.vue'
6
7
  import HstColorShadesVue from './components/design-tokens/HstColorShades.vue'
8
+ import HstTokenListVue from './components/design-tokens/HstTokenList.vue'
9
+ import HstTokenGridVue from './components/design-tokens/HstTokenGrid.vue'
7
10
  import HstCopyIconVue from './components/HstCopyIcon.vue'
8
11
 
9
12
  export const HstCheckbox = HstCheckboxVue
@@ -11,11 +14,17 @@ export const HstText = HstTextVue
11
14
  export const HstNumber = HstNumberVue
12
15
  export const HstTextarea = HstTextareaVue
13
16
  export const HstColorShades = HstColorShadesVue
17
+ export const HstTokenList = HstTokenListVue
18
+ export const HstTokenGrid = HstTokenGridVue
14
19
  export const HstCopyIcon = HstCopyIconVue
15
20
 
16
21
  export function registerVueComponents (app: App) {
17
22
  app.component('HstCheckbox', HstCheckboxVue)
18
23
  app.component('HstText', HstTextVue)
19
24
  app.component('HstNumber', HstNumberVue)
25
+ app.component('HstSelect', HstSelectVue)
20
26
  app.component('HstTextarea', HstTextareaVue)
27
+ app.component('HstColorShades', HstColorShadesVue)
28
+ app.component('HstTokenList', HstTokenListVue)
29
+ app.component('HstTokenGrid', HstTokenGridVue)
21
30
  }