Skip to content

Commit df6904b

Browse files
feat: [Progress] implements
1 parent 099e420 commit df6904b

File tree

17 files changed

+356
-13
lines changed

17 files changed

+356
-13
lines changed

packages/vue-primitives/src/accordion/stories/styles.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
appearance: none;
3737
border: none;
3838
padding: 10px;
39-
background-color: black;
39+
background-color: #111;
4040
color: white;
4141
font-family: inherit;
4242
font-size: 1.2em;
@@ -59,7 +59,7 @@
5959

6060
&:focus {
6161
--shadow-color: #111;
62-
color: black;
62+
color: #111;
6363
}
6464
}
6565

packages/vue-primitives/src/avatar/stories/styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@
2424
align-items: center;
2525
justify-content: center;
2626

27-
background-color: black;
27+
background-color: #111;
2828
color: white;
2929
}

packages/vue-primitives/src/collapsible/stories/styles.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
appearance: none;
1313
border: none;
1414
padding: 10px;
15-
background-color: black;
15+
background-color: #111;
1616
color: white;
1717
font-family: inherit;
1818
font-size: 1.2em;
@@ -34,7 +34,7 @@
3434

3535
&[data-state="open"]:focus {
3636
--shadow-color: #111;
37-
color: black;
37+
color: #111;
3838
}
3939

4040
}

packages/vue-primitives/src/primitive/Primitive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
export const ELEMENT_NODE = globalThis?.Node?.ELEMENT_NODE ?? -1
2-
31
export type AsTag =
42
| 'a'
53
| 'button'
@@ -25,3 +23,5 @@ export interface PrimitiveProps {
2523
as?: AsTag | object
2624
asChild?: boolean
2725
}
26+
27+
export const ELEMENT_NODE = globalThis?.Node?.ELEMENT_NODE ?? -1
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import type { Ref } from 'vue'
2+
import type { PrimitiveProps } from '../primitive/index.ts'
3+
import { createContext } from '../hooks/createContext.ts'
4+
5+
export interface ProgressProps extends PrimitiveProps {
6+
value?: number | null | undefined
7+
max?: number
8+
getValueLabel?: (value: number, max: number) => string
9+
}
10+
11+
type ProgressState = 'indeterminate' | 'complete' | 'loading'
12+
13+
interface ProgressContext {
14+
value: Ref<number | null>
15+
max: Ref<number>
16+
}
17+
18+
export const [provideProgressContext, useProgressContext] = createContext<ProgressContext>('Progress')
19+
20+
export const DEFAULT_MAX = 100
21+
22+
export function defaultGetValueLabel(value: number, max: number) {
23+
return `${Math.round((value / max) * 100)}%`
24+
}
25+
26+
export function getProgressState(value: number | undefined | null, maxValue: number): ProgressState {
27+
return value == null ? 'indeterminate' : value === maxValue ? 'complete' : 'loading'
28+
}
29+
30+
export function isNumber(value: unknown): value is number {
31+
return typeof value === 'number'
32+
}
33+
34+
export function isValidMaxNumber(max: unknown): max is number {
35+
return (
36+
isNumber(max)
37+
&& !Number.isNaN(max)
38+
&& max > 0
39+
)
40+
}
41+
42+
export function isValidValueNumber(value: unknown, max: number): value is number {
43+
return (
44+
isNumber(value)
45+
&& !Number.isNaN(value)
46+
&& value <= max
47+
&& value >= 0
48+
)
49+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<script setup lang="ts">
2+
import { type PropType, computed, toRef } from 'vue'
3+
import { Primitive } from '../primitive/index.ts'
4+
import { DEFAULT_MAX, type ProgressProps, defaultGetValueLabel, getProgressState, isNumber, isValidMaxNumber, isValidValueNumber, provideProgressContext } from './Progress.ts'
5+
6+
defineOptions({
7+
name: 'OkuProgress',
8+
})
9+
10+
const props = defineProps({
11+
as: {
12+
type: [String, Object] as PropType<Required<ProgressProps>['as']>,
13+
required: false,
14+
default: undefined,
15+
},
16+
asChild: {
17+
type: Boolean as PropType<Required<ProgressProps>['asChild']>,
18+
required: false,
19+
default: undefined,
20+
},
21+
value: {
22+
type: [Number, null] as PropType<Required<ProgressProps>['value']>,
23+
required: false,
24+
validator(value, props) {
25+
return isNumber(props.max) && isValidValueNumber(value, props.max)
26+
},
27+
default: null,
28+
},
29+
max: {
30+
type: Number as PropType<Required<ProgressProps>['max']>,
31+
required: false,
32+
validator(value) {
33+
return isValidMaxNumber(value)
34+
},
35+
default: DEFAULT_MAX,
36+
},
37+
getValueLabel: {
38+
type: Function as PropType<Required<ProgressProps>['getValueLabel']>,
39+
required: false,
40+
default: defaultGetValueLabel,
41+
},
42+
})
43+
44+
const valueLabel = computed(() => isNumber(props.value) ? props.getValueLabel(props.value, props.max) : undefined)
45+
46+
provideProgressContext({
47+
value: toRef(props, 'value'),
48+
max: toRef(props, 'max'),
49+
})
50+
</script>
51+
52+
<template>
53+
<Primitive
54+
:as="as"
55+
:as-child="asChild"
56+
:aria-valuemax="max"
57+
:aria-valuemin="0"
58+
:aria-valuenow="isNumber(value) ? value : undefined"
59+
:aria-valuetext="valueLabel"
60+
role="progressbar"
61+
:data-state="getProgressState(value, max)"
62+
:data-value="value ?? undefined"
63+
:data-max="max"
64+
>
65+
<slot />
66+
</Primitive>
67+
</template>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import type { PrimitiveProps } from '../primitive/index.ts'
2+
3+
export interface ProgressIndicatorProps extends PrimitiveProps {
4+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script setup lang="ts">
2+
import Primitive from '../primitive/Primitive.vue'
3+
import { getProgressState, useProgressContext } from './Progress.ts'
4+
import type { ProgressIndicatorProps } from './ProgressIndicator'
5+
6+
defineOptions({
7+
name: 'ProgressIndicator',
8+
})
9+
10+
defineProps<ProgressIndicatorProps>()
11+
12+
const context = useProgressContext()
13+
</script>
14+
15+
<template>
16+
<Primitive
17+
:as="as"
18+
:as-child="asChild"
19+
:data-state="getProgressState(context.value.value, context.max.value)"
20+
:data-value="context.value.value ?? undefined"
21+
:data-max="context.max.value"
22+
>
23+
<slot />
24+
</Primitive>
25+
</template>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as Progress } from './Progress.vue'
2+
export { default as ProgressIndicator } from './ProgressIndicator.vue'
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<script setup lang="ts">
2+
import { Progress, ProgressIndicator } from '../index.ts'
3+
import './styles.css'
4+
</script>
5+
6+
<template>
7+
<div>
8+
<h1>Loading (not started)</h1>
9+
<Progress class="progress_rootClass" :value="0">
10+
<ProgressIndicator class="progress_indicatorClass progress_indicatorPseudos" />
11+
</Progress>
12+
13+
<h1>Loading (started)</h1>
14+
<Progress class="progress_rootClass" :value="30">
15+
<ProgressIndicator class="progress_indicatorClass progress_indicatorPseudos" />
16+
</Progress>
17+
18+
<h1>Indeterminate</h1>
19+
<Progress class="progress_rootClass">
20+
<ProgressIndicator class="progress_indicatorClass progress_indicatorPseudos" />
21+
</Progress>
22+
23+
<h1>Complete</h1>
24+
<Progress class="progress_rootClass" :value="100">
25+
<ProgressIndicator class="progress_indicatorClass progress_indicatorPseudos" />
26+
</Progress>
27+
28+
<h1>State attributes</h1>
29+
<h2>Loading (started)</h2>
30+
<Progress class="progress_rootAttrClass" :value="30">
31+
<ProgressIndicator class="progress_indicatorAttrClass progress_indicatorPseudos" />
32+
</Progress>
33+
34+
<h2>Indeterminate</h2>
35+
<Progress class="progress_rootAttrClass">
36+
<ProgressIndicator class="progress_indicatorAttrClass progress_indicatorPseudos" />
37+
</Progress>
38+
39+
<h2>Complete</h2>
40+
<Progress class="progress_rootAttrClass" :value="100">
41+
<ProgressIndicator class="progress_indicatorAttrClass progress_indicatorPseudos" />
42+
</Progress>
43+
</div>
44+
</template>

0 commit comments

Comments
 (0)