@poveste/controls 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.
- package/LICENSE +22 -0
- package/README.md +5 -0
- package/dist/components/HstCopyIcon.story.vue.d.ts +2 -0
- package/dist/components/HstCopyIcon.vue.d.ts +7 -0
- package/dist/components/HstWrapper.vue.d.ts +20 -0
- package/dist/components/button/HstButton.story.vue.d.ts +2 -0
- package/dist/components/button/HstButton.vue.d.ts +13 -0
- package/dist/components/button/HstButtonGroup.story.vue.d.ts +2 -0
- package/dist/components/button/HstButtonGroup.vue.d.ts +22 -0
- package/dist/components/checkbox/HstCheckbox.story.vue.d.ts +2 -0
- package/dist/components/checkbox/HstCheckbox.vue.d.ts +19 -0
- package/dist/components/checkbox/HstCheckboxList.story.vue.d.ts +2 -0
- package/dist/components/checkbox/HstCheckboxList.vue.d.ts +22 -0
- package/dist/components/checkbox/HstSimpleCheckbox.story.vue.d.ts +2 -0
- package/dist/components/checkbox/HstSimpleCheckbox.vue.d.ts +12 -0
- package/dist/components/colorselect/HstColorSelect.story.vue.d.ts +2 -0
- package/dist/components/colorselect/HstColorSelect.vue.d.ts +19 -0
- package/dist/components/design-tokens/HstColorShades.story.vue.d.ts +2 -0
- package/dist/components/design-tokens/HstColorShades.vue.d.ts +19 -0
- package/dist/components/design-tokens/HstTokenGrid.story.vue.d.ts +2 -0
- package/dist/components/design-tokens/HstTokenGrid.vue.d.ts +26 -0
- package/dist/components/design-tokens/HstTokenList.story.vue.d.ts +2 -0
- package/dist/components/design-tokens/HstTokenList.vue.d.ts +21 -0
- package/dist/components/json/HstJson.story.vue.d.ts +2 -0
- package/dist/components/json/HstJson.vue.d.ts +19 -0
- package/dist/components/number/HstNumber.story.vue.d.ts +2 -0
- package/dist/components/number/HstNumber.vue.d.ts +19 -0
- package/dist/components/radio/HstRadio.story.vue.d.ts +2 -0
- package/dist/components/radio/HstRadio.vue.d.ts +22 -0
- package/dist/components/select/CustomSelect.vue.d.ts +22 -0
- package/dist/components/select/HstSelect.story.vue.d.ts +2 -0
- package/dist/components/select/HstSelect.vue.d.ts +22 -0
- package/dist/components/slider/HstSlider.story.vue.d.ts +2 -0
- package/dist/components/slider/HstSlider.vue.d.ts +16 -0
- package/dist/components/text/HstText.story.vue.d.ts +2 -0
- package/dist/components/text/HstText.vue.d.ts +19 -0
- package/dist/components/textarea/HstTextarea.story.vue.d.ts +2 -0
- package/dist/components/textarea/HstTextarea.vue.d.ts +19 -0
- package/dist/index.d.ts +1047 -0
- package/dist/index.es.css +1 -0
- package/dist/index.es.js +16392 -0
- package/dist/style-standalone.css +973 -0
- package/dist/types.d.ts +4 -0
- package/dist/utils.d.ts +1 -0
- package/package.json +72 -0
- package/postcss.config.cjs +8 -0
- package/src/components/HstCopyIcon.story.vue +26 -0
- package/src/components/HstCopyIcon.vue +38 -0
- package/src/components/HstWrapper.vue +41 -0
- package/src/components/button/HstButton.story.vue +30 -0
- package/src/components/button/HstButton.vue +26 -0
- package/src/components/button/HstButtonGroup.story.vue +79 -0
- package/src/components/button/HstButtonGroup.vue +71 -0
- package/src/components/checkbox/HstCheckbox.spec.ts +28 -0
- package/src/components/checkbox/HstCheckbox.story.vue +47 -0
- package/src/components/checkbox/HstCheckbox.vue +56 -0
- package/src/components/checkbox/HstCheckboxList.story.vue +49 -0
- package/src/components/checkbox/HstCheckboxList.vue +82 -0
- package/src/components/checkbox/HstSimpleCheckbox.story.vue +28 -0
- package/src/components/checkbox/HstSimpleCheckbox.vue +82 -0
- package/src/components/checkbox/__snapshots__/HstCheckbox.spec.ts.snap +5 -0
- package/src/components/colorselect/HstColorSelect.story.vue +28 -0
- package/src/components/colorselect/HstColorSelect.vue +89 -0
- package/src/components/design-tokens/HstColorShades.story.vue +392 -0
- package/src/components/design-tokens/HstColorShades.vue +101 -0
- package/src/components/design-tokens/HstTokenGrid.story.vue +36 -0
- package/src/components/design-tokens/HstTokenGrid.vue +88 -0
- package/src/components/design-tokens/HstTokenList.story.vue +81 -0
- package/src/components/design-tokens/HstTokenList.vue +62 -0
- package/src/components/json/HstJson.story.vue +41 -0
- package/src/components/json/HstJson.vue +151 -0
- package/src/components/number/HstNumber.story.vue +42 -0
- package/src/components/number/HstNumber.vue +95 -0
- package/src/components/radio/HstRadio.story.vue +51 -0
- package/src/components/radio/HstRadio.vue +109 -0
- package/src/components/select/CustomSelect.vue +119 -0
- package/src/components/select/HstSelect.story.vue +161 -0
- package/src/components/select/HstSelect.vue +40 -0
- package/src/components/slider/HstSlider.story.vue +37 -0
- package/src/components/slider/HstSlider.vue +103 -0
- package/src/components/text/HstText.story.vue +63 -0
- package/src/components/text/HstText.vue +44 -0
- package/src/components/textarea/HstTextarea.story.vue +35 -0
- package/src/components/textarea/HstTextarea.vue +44 -0
- package/src/end.d.ts +8 -0
- package/src/index.ts +54 -0
- package/src/style/main.css +17 -0
- package/src/types.ts +4 -0
- package/src/utils.ts +12 -0
- package/tailwind.config.cjs +13 -0
- package/tsconfig.json +53 -0
- package/vite.config.ts +46 -0
package/dist/types.d.ts
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isDark: import("vue").Ref<boolean, boolean>;
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@poveste/controls",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Prebuilt controls components",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Sorin Gitlan"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": {
|
|
11
|
+
"url": "https://github.com/poveste-dev/poveste.git",
|
|
12
|
+
"type": "git",
|
|
13
|
+
"directory": "packages/poveste-controls"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": [
|
|
19
|
+
"*.css",
|
|
20
|
+
"*.postcss",
|
|
21
|
+
"*.vue"
|
|
22
|
+
],
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"default": "./dist/index.es.js"
|
|
27
|
+
},
|
|
28
|
+
"./*": "./*"
|
|
29
|
+
},
|
|
30
|
+
"main": "./dist/index.es.js",
|
|
31
|
+
"module": "./dist/index.es.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@codemirror/commands": "^6.7.1",
|
|
35
|
+
"@codemirror/lang-json": "^6.0.1",
|
|
36
|
+
"@codemirror/language": "^6.10.6",
|
|
37
|
+
"@codemirror/lint": "^6.8.4",
|
|
38
|
+
"@codemirror/state": "^6.4.1",
|
|
39
|
+
"@codemirror/theme-one-dark": "^6.1.2",
|
|
40
|
+
"@codemirror/view": "^6.35.0",
|
|
41
|
+
"@poveste/shared": "^0.1.0",
|
|
42
|
+
"@poveste/vendors": "^0.1.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.10.1",
|
|
46
|
+
"@vitejs/plugin-vue": "^5.2.1",
|
|
47
|
+
"@vue/runtime-dom": "^3.5.26",
|
|
48
|
+
"@vue/test-utils": "^2.4.6",
|
|
49
|
+
"@vueuse/core": "^12.0.0",
|
|
50
|
+
"autoprefixer": "^10.4.20",
|
|
51
|
+
"concurrently": "^9.1.0",
|
|
52
|
+
"floating-vue": "5.2.2",
|
|
53
|
+
"jsdom": "^27.4.0",
|
|
54
|
+
"postcss": "^8.4.49",
|
|
55
|
+
"postcss-import": "^16.1.0",
|
|
56
|
+
"tailwindcss": "^3.4.16",
|
|
57
|
+
"typescript": "5.6.3",
|
|
58
|
+
"vite": "^7.3.0",
|
|
59
|
+
"vitest": "4.0.16",
|
|
60
|
+
"vue": "^3.5.26",
|
|
61
|
+
"vue-tsc": "^2.1.10"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "rimraf dist && pnpm run build:css && vite build && pnpm run build:types",
|
|
65
|
+
"build:css": "tailwindcss -i src/style/main.css -o ./dist/style-standalone.css -c tailwind.config.cjs --postcss postcss.config.cjs",
|
|
66
|
+
"build:types": "vue-tsc --declaration --emitDeclarationOnly",
|
|
67
|
+
"watch": "concurrently \"vite build --watch\" \"pnpm run build:types --watch\"",
|
|
68
|
+
"watch:full": "concurrently \"vite build --watch\" \"pnpm run build:css --watch\" \"pnpm run build:types --watch\"",
|
|
69
|
+
"test": "vitest run",
|
|
70
|
+
"test:dev": "vitest"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import HstCopyIcon from './HstCopyIcon.vue'
|
|
3
|
+
|
|
4
|
+
function initState() {
|
|
5
|
+
return {
|
|
6
|
+
content: 'Text fo copy',
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<Story
|
|
13
|
+
title="internals/HstCopyIcon"
|
|
14
|
+
>
|
|
15
|
+
<Variant
|
|
16
|
+
title="default"
|
|
17
|
+
:init-state="initState"
|
|
18
|
+
>
|
|
19
|
+
<template #default="{ state }">
|
|
20
|
+
<HstCopyIcon
|
|
21
|
+
:content="state.content"
|
|
22
|
+
/>
|
|
23
|
+
</template>
|
|
24
|
+
</Variant>
|
|
25
|
+
</Story>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default {
|
|
3
|
+
name: 'HstCopyIcon',
|
|
4
|
+
}
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import type { Awaitable } from '@poveste/shared'
|
|
9
|
+
import { Icon } from '@iconify/vue'
|
|
10
|
+
import { useClipboard } from '@vueuse/core'
|
|
11
|
+
import { VTooltip as vTooltip } from 'floating-vue'
|
|
12
|
+
|
|
13
|
+
const props = defineProps<{
|
|
14
|
+
content: string | (() => Awaitable<string>)
|
|
15
|
+
}>()
|
|
16
|
+
|
|
17
|
+
const { copy, copied } = useClipboard()
|
|
18
|
+
|
|
19
|
+
async function action() {
|
|
20
|
+
const content = typeof props.content === 'function' ? await props.content() : props.content
|
|
21
|
+
copy(content)
|
|
22
|
+
}
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<Icon
|
|
27
|
+
v-tooltip="{
|
|
28
|
+
content: 'Copied!',
|
|
29
|
+
triggers: [],
|
|
30
|
+
shown: copied,
|
|
31
|
+
distance: 12,
|
|
32
|
+
delay: 0,
|
|
33
|
+
}"
|
|
34
|
+
icon="carbon:copy-file"
|
|
35
|
+
class="htw-w-4 htw-h-4 htw-opacity-50 hover:htw-opacity-100 hover:htw-text-primary-500 htw-cursor-pointer"
|
|
36
|
+
@click="action()"
|
|
37
|
+
/>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
withDefaults(defineProps<{
|
|
11
|
+
title?: string
|
|
12
|
+
tag?: string
|
|
13
|
+
}>(), {
|
|
14
|
+
title: undefined,
|
|
15
|
+
tag: 'label',
|
|
16
|
+
})
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<component
|
|
21
|
+
:is="tag"
|
|
22
|
+
class="histoire-wrapper htw-p-2 hover:htw-bg-primary-100 dark:hover:htw-bg-primary-800 htw-flex htw-gap-2 htw-flex-wrap"
|
|
23
|
+
>
|
|
24
|
+
<span
|
|
25
|
+
v-tooltip="{
|
|
26
|
+
content: title,
|
|
27
|
+
placement: 'left',
|
|
28
|
+
distance: 12,
|
|
29
|
+
}"
|
|
30
|
+
class="htw-w-28 htw-whitespace-nowrap htw-text-ellipsis htw-overflow-hidden htw-shrink-0"
|
|
31
|
+
>
|
|
32
|
+
{{ title }}
|
|
33
|
+
</span>
|
|
34
|
+
<span class="htw-grow htw-max-w-full htw-flex htw-items-center htw-gap-1">
|
|
35
|
+
<span class="htw-block htw-grow htw-max-w-full">
|
|
36
|
+
<slot />
|
|
37
|
+
</span>
|
|
38
|
+
<slot name="actions" />
|
|
39
|
+
</span>
|
|
40
|
+
</component>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import HstButton from './HstButton.vue'
|
|
3
|
+
|
|
4
|
+
const variants: Array<{ name: string, bind?: unknown }> = [
|
|
5
|
+
{ name: 'Default' },
|
|
6
|
+
{ name: 'Primary', bind: { color: 'primary' } },
|
|
7
|
+
{ name: 'Flat', bind: { color: 'flat' } },
|
|
8
|
+
]
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<Story
|
|
13
|
+
title="HstButton"
|
|
14
|
+
group="controls"
|
|
15
|
+
:layout="{ type: 'grid', width: '200px', iframe: false }"
|
|
16
|
+
>
|
|
17
|
+
<Variant
|
|
18
|
+
v-for="(variant, key) of variants"
|
|
19
|
+
:key="key"
|
|
20
|
+
:title="variant.name"
|
|
21
|
+
>
|
|
22
|
+
<HstButton
|
|
23
|
+
v-bind="variant.bind as {}"
|
|
24
|
+
class="htw-p-2"
|
|
25
|
+
>
|
|
26
|
+
Click me!
|
|
27
|
+
</HstButton>
|
|
28
|
+
</Variant>
|
|
29
|
+
</Story>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default {
|
|
3
|
+
name: 'HstButton',
|
|
4
|
+
}
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
const colors = {
|
|
9
|
+
default: 'htw-bg-gray-200 dark:htw-bg-gray-750 htw-text-gray-900 dark:htw-text-gray-100 hover:htw-bg-primary-200 dark:hover:htw-bg-primary-900',
|
|
10
|
+
primary: 'htw-bg-primary-500 hover:htw-bg-primary-600 htw-text-white dark:htw-text-black',
|
|
11
|
+
flat: 'htw-bg-transparent hover:htw-bg-gray-500/20 htw-text-gray-900 dark:htw-text-gray-100',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
defineProps<{
|
|
15
|
+
color?: keyof typeof colors
|
|
16
|
+
}>()
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<button
|
|
21
|
+
class="histoire-button htw-cursor-pointer htw-rounded-sm htw-border-none"
|
|
22
|
+
:class="colors[color ?? 'default']"
|
|
23
|
+
>
|
|
24
|
+
<slot />
|
|
25
|
+
</button>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import HstButtonGroup from './HstButtonGroup.vue'
|
|
4
|
+
|
|
5
|
+
const options = {
|
|
6
|
+
slow: 'Slow',
|
|
7
|
+
fast: 'Fast',
|
|
8
|
+
max: 'Max',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const flatOptions = Object.keys(options)
|
|
12
|
+
|
|
13
|
+
const objectOptions = Object.keys(options).map(key => ({
|
|
14
|
+
label: options[key],
|
|
15
|
+
value: key,
|
|
16
|
+
}))
|
|
17
|
+
|
|
18
|
+
function initState() {
|
|
19
|
+
return {
|
|
20
|
+
speed: flatOptions[0],
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const count = ref('0')
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<Story
|
|
29
|
+
title="HstButtonGroup"
|
|
30
|
+
group="controls"
|
|
31
|
+
:layout="{ type: 'single', iframe: false }"
|
|
32
|
+
>
|
|
33
|
+
<Variant
|
|
34
|
+
title="playground"
|
|
35
|
+
:init-state="initState"
|
|
36
|
+
>
|
|
37
|
+
<template #default="{ state }">
|
|
38
|
+
<pre>{{ { speed: state.speed } }}</pre>
|
|
39
|
+
<HstButtonGroup
|
|
40
|
+
v-model="state.speed"
|
|
41
|
+
title="Label"
|
|
42
|
+
:options="objectOptions"
|
|
43
|
+
/>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<template #controls="{ state }">
|
|
47
|
+
<HstButtonGroup
|
|
48
|
+
v-model="state.speed"
|
|
49
|
+
title="Label"
|
|
50
|
+
:options="objectOptions"
|
|
51
|
+
/>
|
|
52
|
+
</template>
|
|
53
|
+
</Variant>
|
|
54
|
+
|
|
55
|
+
<Variant
|
|
56
|
+
title="Object options"
|
|
57
|
+
:init-state="initState"
|
|
58
|
+
>
|
|
59
|
+
<template #default="{ state }">
|
|
60
|
+
<pre>{{ { speed: state.speed } }}</pre>
|
|
61
|
+
<HstButtonGroup
|
|
62
|
+
v-model="state.speed"
|
|
63
|
+
title="Label"
|
|
64
|
+
:options="options"
|
|
65
|
+
/>
|
|
66
|
+
</template>
|
|
67
|
+
</Variant>
|
|
68
|
+
|
|
69
|
+
<Variant
|
|
70
|
+
title="Should retain order"
|
|
71
|
+
>
|
|
72
|
+
<pre>{{ { count } }}</pre>
|
|
73
|
+
<HstButtonGroup
|
|
74
|
+
v-model="count"
|
|
75
|
+
:options="[{ label: 'Low', value: '-25' }, { label: 'Regular', value: '0' }, { label: 'High', value: '200' }]"
|
|
76
|
+
/>
|
|
77
|
+
</Variant>
|
|
78
|
+
</Story>
|
|
79
|
+
</template>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default {
|
|
3
|
+
name: 'HstButtonGroup',
|
|
4
|
+
}
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import type { ComputedRef } from 'vue'
|
|
9
|
+
import type { HstControlOption } from '../../types'
|
|
10
|
+
import { computed } from 'vue'
|
|
11
|
+
import HstWrapper from '../HstWrapper.vue'
|
|
12
|
+
import HstButton from './HstButton.vue'
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
title?: string
|
|
16
|
+
modelValue?: string
|
|
17
|
+
options: string[] | number[] | HstControlOption[] | Record<string, string | number>
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const formattedOptions: ComputedRef<HstControlOption[]> = computed(() => {
|
|
21
|
+
if (Array.isArray(props.options)) {
|
|
22
|
+
return props.options.map((value: string | number | HstControlOption) => {
|
|
23
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
24
|
+
return { value, label: String(value) }
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
return value
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
return Object.keys(props.options).map((value: string) => ({
|
|
33
|
+
value,
|
|
34
|
+
label: props.options[value],
|
|
35
|
+
}))
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const emit = defineEmits<{
|
|
40
|
+
(e: 'update:modelValue', value: string): void
|
|
41
|
+
}>()
|
|
42
|
+
|
|
43
|
+
function selectOption(value: string) {
|
|
44
|
+
emit('update:modelValue', value)
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<HstWrapper
|
|
50
|
+
tag="div"
|
|
51
|
+
role="group"
|
|
52
|
+
:title="title"
|
|
53
|
+
class="histoire-button-group htw-flex-nowrap htw-items-center"
|
|
54
|
+
>
|
|
55
|
+
<div class="htw-flex htw-gap-px htw-border htw-border-solid htw-border-black/25 dark:htw-border-white/25 htw-rounded-sm htw-p-px">
|
|
56
|
+
<HstButton
|
|
57
|
+
v-for="{ label, value } of formattedOptions"
|
|
58
|
+
:key="value"
|
|
59
|
+
class="htw-px-1 htw-h-[22px] htw-flex-1 !htw-rounded-[3px]"
|
|
60
|
+
:color="value === modelValue ? 'primary' : 'flat'"
|
|
61
|
+
:rounded="false"
|
|
62
|
+
@click="selectOption(value)"
|
|
63
|
+
>
|
|
64
|
+
{{ label }}
|
|
65
|
+
</HstButton>
|
|
66
|
+
</div>
|
|
67
|
+
<template #actions>
|
|
68
|
+
<slot name="actions" />
|
|
69
|
+
</template>
|
|
70
|
+
</HstWrapper>
|
|
71
|
+
</template>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils'
|
|
2
|
+
import HstCheckbox from './HstCheckbox.vue'
|
|
3
|
+
|
|
4
|
+
describe('hstCheckbox', () => {
|
|
5
|
+
it('toggle to checked', async () => {
|
|
6
|
+
const wrapper = mount(HstCheckbox, {
|
|
7
|
+
props: {
|
|
8
|
+
modelValue: false,
|
|
9
|
+
title: 'Label',
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
await wrapper.trigger('click')
|
|
13
|
+
expect(wrapper.emitted('update:modelValue')[0]).toEqual([true])
|
|
14
|
+
expect(wrapper.html()).toMatchSnapshot()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('toggle to unchecked', async () => {
|
|
18
|
+
const wrapper = mount(HstCheckbox, {
|
|
19
|
+
props: {
|
|
20
|
+
modelValue: true,
|
|
21
|
+
title: 'Label',
|
|
22
|
+
},
|
|
23
|
+
})
|
|
24
|
+
await wrapper.trigger('click')
|
|
25
|
+
expect(wrapper.emitted('update:modelValue')[0]).toEqual([false])
|
|
26
|
+
expect(wrapper.html()).toMatchSnapshot()
|
|
27
|
+
})
|
|
28
|
+
})
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import HstCheckbox from './HstCheckbox.vue'
|
|
3
|
+
|
|
4
|
+
function initState() {
|
|
5
|
+
return {
|
|
6
|
+
booleanChecked: false,
|
|
7
|
+
stringChecked: 'false',
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<Story
|
|
14
|
+
title="HstCheckbox"
|
|
15
|
+
group="controls"
|
|
16
|
+
:layout="{ type: 'single', iframe: false }"
|
|
17
|
+
>
|
|
18
|
+
<Variant
|
|
19
|
+
title="playground"
|
|
20
|
+
:init-state="initState"
|
|
21
|
+
>
|
|
22
|
+
<template #default="{ state }">
|
|
23
|
+
<HstCheckbox
|
|
24
|
+
v-model="state.booleanChecked"
|
|
25
|
+
title="Boolean"
|
|
26
|
+
/>
|
|
27
|
+
{{ { value: state.booleanChecked } }}
|
|
28
|
+
<HstCheckbox
|
|
29
|
+
v-model="state.stringChecked"
|
|
30
|
+
title="String"
|
|
31
|
+
/>
|
|
32
|
+
{{ { value: state.stringChecked } }}
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<template #controls="{ state }">
|
|
36
|
+
<HstCheckbox
|
|
37
|
+
v-model="state.booleanChecked"
|
|
38
|
+
title="Boolean"
|
|
39
|
+
/>
|
|
40
|
+
<HstCheckbox
|
|
41
|
+
v-model="state.stringChecked"
|
|
42
|
+
title="String"
|
|
43
|
+
/>
|
|
44
|
+
</template>
|
|
45
|
+
</Variant>
|
|
46
|
+
</Story>
|
|
47
|
+
</template>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default {
|
|
3
|
+
name: 'HstCheckbox',
|
|
4
|
+
}
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { computed } from 'vue'
|
|
9
|
+
import HstWrapper from '../HstWrapper.vue'
|
|
10
|
+
import HstSimpleCheckbox from './HstSimpleCheckbox.vue'
|
|
11
|
+
|
|
12
|
+
type Booleanish = boolean | 'true' | 'false'
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
modelValue?: Booleanish | null
|
|
16
|
+
title?: string
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
const emit = defineEmits({
|
|
20
|
+
'update:modelValue': (newValue: Booleanish) => true,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
function toggle() {
|
|
24
|
+
if (typeof props.modelValue === 'string') {
|
|
25
|
+
emit('update:modelValue', props.modelValue === 'false' ? 'true' : 'false')
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
emit('update:modelValue', !props.modelValue)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const isTrue = computed(() => {
|
|
33
|
+
if (typeof props.modelValue === 'string') {
|
|
34
|
+
return props.modelValue !== 'false'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return props.modelValue
|
|
38
|
+
})
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<HstWrapper
|
|
43
|
+
role="checkbox"
|
|
44
|
+
tabindex="0"
|
|
45
|
+
class="histoire-checkbox htw-cursor-pointer htw-items-center"
|
|
46
|
+
:title="title"
|
|
47
|
+
@click="toggle()"
|
|
48
|
+
@keydown.enter.prevent="toggle()"
|
|
49
|
+
@keydown.space.prevent="toggle()"
|
|
50
|
+
>
|
|
51
|
+
<HstSimpleCheckbox :model-value="isTrue" />
|
|
52
|
+
<template #actions>
|
|
53
|
+
<slot name="actions" />
|
|
54
|
+
</template>
|
|
55
|
+
</HstWrapper>
|
|
56
|
+
</template>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import HstCheckboxList from './HstCheckboxList.vue'
|
|
3
|
+
|
|
4
|
+
const options = {
|
|
5
|
+
'crash-bandicoot': 'Crash Bandicoot',
|
|
6
|
+
'the-last-of-us': 'The Last of Us',
|
|
7
|
+
'ghost-of-tsushima': 'Ghost of Tsushima',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const objectOptions = Object.keys(options).map(key => ({
|
|
11
|
+
label: options[key],
|
|
12
|
+
value: key,
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
function initState() {
|
|
16
|
+
return {
|
|
17
|
+
characters: [],
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<Story
|
|
24
|
+
title="HstCheckboxList"
|
|
25
|
+
group="controls"
|
|
26
|
+
:layout="{ type: 'single', iframe: false }"
|
|
27
|
+
>
|
|
28
|
+
<Variant
|
|
29
|
+
title="playground"
|
|
30
|
+
:init-state="initState"
|
|
31
|
+
>
|
|
32
|
+
<template #default="{ state }">
|
|
33
|
+
<HstCheckboxList
|
|
34
|
+
v-model="state.characters"
|
|
35
|
+
title="Label"
|
|
36
|
+
:options="objectOptions"
|
|
37
|
+
/>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<template #controls="{ state }">
|
|
41
|
+
<HstCheckboxList
|
|
42
|
+
v-model="state.characters"
|
|
43
|
+
title="Label"
|
|
44
|
+
:options="objectOptions"
|
|
45
|
+
/>
|
|
46
|
+
</template>
|
|
47
|
+
</Variant>
|
|
48
|
+
</Story>
|
|
49
|
+
</template>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export default {
|
|
3
|
+
name: 'HstCheckboxList',
|
|
4
|
+
}
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import type { ComputedRef } from 'vue'
|
|
9
|
+
import type { HstControlOption } from '../../types'
|
|
10
|
+
import { computed } from 'vue'
|
|
11
|
+
import HstWrapper from '../HstWrapper.vue'
|
|
12
|
+
import HstSimpleCheckbox from './HstSimpleCheckbox.vue'
|
|
13
|
+
|
|
14
|
+
const props = defineProps<{
|
|
15
|
+
title?: string
|
|
16
|
+
modelValue: Array<string>
|
|
17
|
+
options: string[] | HstControlOption[]
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const formattedOptions: ComputedRef<Record<string, string>> = computed(() => {
|
|
21
|
+
if (Array.isArray(props.options)) {
|
|
22
|
+
return Object.fromEntries(props.options.map((value: string | HstControlOption) => {
|
|
23
|
+
if (typeof value === 'string') {
|
|
24
|
+
return [value, value]
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
return [value.value, value.label]
|
|
28
|
+
}
|
|
29
|
+
}))
|
|
30
|
+
}
|
|
31
|
+
return props.options
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const emit = defineEmits<{
|
|
35
|
+
(e: 'update:modelValue', value: Array<string>): void
|
|
36
|
+
}>()
|
|
37
|
+
|
|
38
|
+
function toggleOption(value: string) {
|
|
39
|
+
if (props.modelValue.includes(value)) {
|
|
40
|
+
emit('update:modelValue', props.modelValue.filter(element => element !== value))
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
emit('update:modelValue', [...props.modelValue, value])
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<HstWrapper
|
|
50
|
+
role="group"
|
|
51
|
+
:title="title"
|
|
52
|
+
class="histoire-checkbox-list htw-cursor-text"
|
|
53
|
+
:class="$attrs.class"
|
|
54
|
+
:style="$attrs.style"
|
|
55
|
+
>
|
|
56
|
+
<div class="-htw-my-1">
|
|
57
|
+
<template
|
|
58
|
+
v-for="(label, value) in formattedOptions"
|
|
59
|
+
:key="value"
|
|
60
|
+
>
|
|
61
|
+
<label
|
|
62
|
+
tabindex="0"
|
|
63
|
+
:for="`${value}-radio`"
|
|
64
|
+
class="htw-cursor-pointer htw-flex htw-items-center htw-relative htw-py-1 htw-group"
|
|
65
|
+
@keydown.enter.prevent="toggleOption(value)"
|
|
66
|
+
@keydown.space.prevent="toggleOption(value)"
|
|
67
|
+
@click="toggleOption(value)"
|
|
68
|
+
>
|
|
69
|
+
<HstSimpleCheckbox
|
|
70
|
+
:model-value="modelValue.includes(value)"
|
|
71
|
+
class="htw-mr-2"
|
|
72
|
+
/>
|
|
73
|
+
{{ label }}
|
|
74
|
+
</label>
|
|
75
|
+
</template>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<template #actions>
|
|
79
|
+
<slot name="actions" />
|
|
80
|
+
</template>
|
|
81
|
+
</HstWrapper>
|
|
82
|
+
</template>
|