diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 2d0c32cd..764ba898 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -2,6 +2,8 @@ module.exports = {
root: true,
extends: ['@nuxt/eslint-config'],
rules: {
+ 'comma-dangle': ['error', 'never'],
+ 'space-before-function-paren': ['error', 'always'],
'vue/multi-word-component-names': 0,
'vue/max-attributes-per-line': ['error', {
singleline: {
diff --git a/.gitignore b/.gitignore
index 544a23ab..df00b332 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ dist
.DS_Store
.history
.vercel
+.idea
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 00000000..c50384fb
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,6 @@
+{
+ "trailingComma": "none",
+ "tabWidth": 2,
+ "semi": false,
+ "singleQuote": true
+}
diff --git a/docs/components/content/examples/RangeExample.vue b/docs/components/content/examples/RangeExample.vue
new file mode 100644
index 00000000..a5aeda29
--- /dev/null
+++ b/docs/components/content/examples/RangeExample.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/docs/content/1.getting-started/3.theming.md b/docs/content/1.getting-started/3.theming.md
index 512ecf38..5167c8de 100644
--- a/docs/content/1.getting-started/3.theming.md
+++ b/docs/content/1.getting-started/3.theming.md
@@ -33,7 +33,7 @@ Likewise, you can't define a `primary` color in your `tailwind.config.ts` as it
We'd advise you to use those colors in your components and pages, e.g. `text-primary-500 dark:text-primary-400`, `bg-gray-100 dark:bg-gray-900`, etc. so your app automatically adapts when changing your `app.config.ts`.
::
-Components having a `color` prop like [Avatar](/elements/avatar#chip), [Badge](/elements/badge#style), [Button](/elements/button#style), [Input](/elements/input#style) (inherited in [Select](/forms/select) and [SelectMenu](/forms/select-menu)) and [Notification](/overlays/notification#timeout) will use the `primary` color by default but will handle all the colors defined in your `tailwind.config.ts` or the default Tailwind CSS colors.
+Components having a `color` prop like [Avatar](/elements/avatar#chip), [Badge](/elements/badge#style), [Button](/elements/button#style), [Input](/elements/input#style) (inherited in [Select](/forms/select) and [SelectMenu](/forms/select-menu)), [Range](/forms/range) and [Notification](/overlays/notification#timeout) will use the `primary` color by default but will handle all the colors defined in your `tailwind.config.ts` or the default Tailwind CSS colors.
Variant classes of those components are defined with a syntax like `bg-{color}-500 dark:bg-{color}-400` so they can be used with any color. However, this means that Tailwind will not find those classes and therefore will not generate the corresponding CSS.
diff --git a/docs/content/3.forms/8.range.md b/docs/content/3.forms/8.range.md
new file mode 100644
index 00000000..1bf519e9
--- /dev/null
+++ b/docs/content/3.forms/8.range.md
@@ -0,0 +1,101 @@
+---
+github: true
+description: Display a range field
+navigation:
+ badge: "Edge"
+---
+
+## Usage
+
+Use a `v-model` to make the Range reactive.
+
+::component-example
+#default
+:range-example
+
+#code
+```vue
+
+
+
+
+
+```
+::
+
+### Style
+
+Use the `color` prop to change the visual style of the Range.
+
+::component-card
+---
+baseProps:
+ name: range'
+ placeholder: 'Search...'
+props:
+ color: 'primary'
+---
+::
+
+### Size
+
+Use the `size` prop to change the size of the Range.
+
+::component-card
+---
+baseProps:
+ name: 'range'
+props:
+ size: 'md'
+---
+::
+
+### Disabled
+
+Use the `disabled` prop to disable the Range.
+
+::component-card
+---
+baseProps:
+ name: 'range'
+props:
+ disabled: true
+---
+::
+
+### Min and Max
+
+Use the `min` and `max` prop to configure the Range.
+
+::component-card
+---
+baseProps:
+ name: 'range'
+props:
+ min: 0
+ max: 100
+---
+::
+
+### Step
+
+Use the `step` prop to change the step increment.
+
+::component-card
+---
+baseProps:
+ name: 'range'
+props:
+ step: 20
+---
+::
+
+## Props
+
+:component-props
+
+## Preset
+
+:component-preset
diff --git a/docs/content/3.forms/8.form-group.md b/docs/content/3.forms/9.form-group.md
similarity index 100%
rename from docs/content/3.forms/8.form-group.md
rename to docs/content/3.forms/9.form-group.md
diff --git a/src/colors.ts b/src/colors.ts
index a4c93bcf..093e7d26 100644
--- a/src/colors.ts
+++ b/src/colors.ts
@@ -27,26 +27,26 @@ const kebabCase = (str: string) => {
const safelistByComponent = {
avatar: (colorsAsRegex) => [{
- pattern: new RegExp(`bg-(${colorsAsRegex})-500`)
- }, {
pattern: new RegExp(`bg-(${colorsAsRegex})-400`),
variants: ['dark']
+ }, {
+ pattern: new RegExp(`bg-(${colorsAsRegex})-500`)
}],
badge: (colorsAsRegex) => [{
pattern: new RegExp(`bg-(${colorsAsRegex})-50`)
}, {
pattern: new RegExp(`bg-(${colorsAsRegex})-400`),
variants: ['dark']
- }, {
- pattern: new RegExp(`text-(${colorsAsRegex})-500`)
}, {
pattern: new RegExp(`text-(${colorsAsRegex})-400`),
variants: ['dark']
}, {
- pattern: new RegExp(`ring-(${colorsAsRegex})-500`)
+ pattern: new RegExp(`text-(${colorsAsRegex})-500`)
}, {
pattern: new RegExp(`ring-(${colorsAsRegex})-400`),
variants: ['dark']
+ }, {
+ pattern: new RegExp(`ring-(${colorsAsRegex})-500`)
}],
button: (colorsAsRegex) => [{
pattern: new RegExp(`bg-(${colorsAsRegex})-50`),
@@ -103,16 +103,33 @@ const safelistByComponent = {
pattern: new RegExp(`ring-(${colorsAsRegex})-500`),
variants: ['focus']
}],
- notification: (colorsAsRegex) => [{
+ range: (colorsAsRegex) => [{
+ pattern: new RegExp(`bg-(${colorsAsRegex})-400`),
+ variants: ['dark']
+ }, {
pattern: new RegExp(`bg-(${colorsAsRegex})-500`)
}, {
- pattern: new RegExp(`bg-(${colorsAsRegex})-400`),
+ pattern: new RegExp(`text-(${colorsAsRegex})-400`),
variants: ['dark']
}, {
pattern: new RegExp(`text-(${colorsAsRegex})-500`)
+ }, {
+ pattern: new RegExp(`ring-(${colorsAsRegex})-400`),
+ variants: ['dark:focus-visible']
+ }, {
+ pattern: new RegExp(`ring-(${colorsAsRegex})-500`),
+ variants: ['focus-visible']
+ }],
+ notification: (colorsAsRegex) => [{
+ pattern: new RegExp(`bg-(${colorsAsRegex})-400`),
+ variants: ['dark']
+ }, {
+ pattern: new RegExp(`bg-(${colorsAsRegex})-500`)
}, {
pattern: new RegExp(`text-(${colorsAsRegex})-400`),
variants: ['dark']
+ }, {
+ pattern: new RegExp(`text-(${colorsAsRegex})-500`)
}]
}
@@ -127,7 +144,7 @@ const colorsAsRegex = (colors: string[]): string => colors.join('|')
export const excludeColors = (colors: object) => Object.keys(omit(colors, colorsToExclude)).map(color => kebabCase(color)) as string[]
export const generateSafelist = (colors: string[]) => {
- const safelist = ['avatar', 'badge', 'button', 'input', 'notification'].flatMap(component => safelistByComponent[component](colorsAsRegex(colors)))
+ const safelist = ['avatar', 'badge', 'button', 'input', 'range', 'notification'].flatMap(component => safelistByComponent[component](colorsAsRegex(colors)))
return [
...safelist,
diff --git a/src/runtime/app.config.ts b/src/runtime/app.config.ts
index c4dd4fc9..ce287dae 100644
--- a/src/runtime/app.config.ts
+++ b/src/runtime/app.config.ts
@@ -327,10 +327,10 @@ const input = {
},
color: {
white: {
- outline: 'shadow-sm bg-white dark:bg-gray-900 text-gray-900 dark:text-white ring-1 ring-inset ring-gray-300 dark:ring-gray-700 focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400',
+ outline: 'shadow-sm bg-white dark:bg-gray-900 text-gray-900 dark:text-white ring-1 ring-inset ring-gray-300 dark:ring-gray-700 focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400'
},
gray: {
- outline: 'shadow-sm bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-white ring-1 ring-inset ring-gray-300 dark:ring-gray-700 focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400',
+ outline: 'shadow-sm bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-white ring-1 ring-inset ring-gray-300 dark:ring-gray-700 focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400'
}
},
variant: {
@@ -400,7 +400,7 @@ const textarea = {
default: {
size: 'sm',
color: 'white',
- variant: 'outline',
+ variant: 'outline'
}
}
@@ -510,6 +510,39 @@ const toggle = {
}
}
+const range = {
+ wrapper: 'relative w-full',
+ base: 'w-full absolute appearance-none cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none [&::-webkit-slider-runnable-track]:h-full [&::-moz-slider-runnable-track]:h-full',
+ background: 'bg-gray-200 dark:bg-gray-700',
+ rounded: 'rounded-lg',
+ ring: 'focus-visible:ring-2 focus-visible:ring-{color}-500 dark:focus-visible:ring-{color}-400 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-gray-900',
+ progress: {
+ base: 'absolute inset-0 h-full pointer-events-none',
+ rounded: 'rounded-l-lg',
+ background: 'bg-{color}-500 dark:bg-{color}-400'
+ },
+ thumb: {
+ base: `[&::-webkit-slider-thumb]:relative [&::-moz-range-thumb]:relative [&::-webkit-slider-thumb]:z-[1] [&::-moz-range-thumb]:z-[1] [&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0`,
+ color: 'text-{color}-500 dark:text-{color}-400',
+ background: '[&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:dark:bg-gray-900 [&::-moz-range-thumb]:bg-current',
+ ring: '[&::-webkit-slider-thumb]:ring-2 [&::-webkit-slider-thumb]:ring-current',
+ size: {
+ sm: '[&::-webkit-slider-thumb]:h-3 [&::-moz-range-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-moz-range-thumb]:w-3 [&::-webkit-slider-thumb]:-mt-1 [&::-moz-range-thumb]:-mt-1',
+ md: '[&::-webkit-slider-thumb]:h-4 [&::-moz-range-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-moz-range-thumb]:w-4 [&::-webkit-slider-thumb]:-mt-1 [&::-moz-range-thumb]:-mt-1',
+ lg: '[&::-webkit-slider-thumb]:h-5 [&::-moz-range-thumb]:h-5 [&::-webkit-slider-thumb]:w-5 [&::-moz-range-thumb]:w-5 [&::-webkit-slider-thumb]:-mt-1 [&::-moz-range-thumb]:-mt-1'
+ }
+ },
+ size: {
+ sm: 'h-1',
+ md: 'h-2',
+ lg: 'h-3'
+ },
+ default: {
+ size: 'md',
+ color: 'primary'
+ }
+}
+
// Layout
const card = {
@@ -872,6 +905,7 @@ export default {
checkbox,
radio,
toggle,
+ range,
card,
container,
skeleton,
diff --git a/src/runtime/components/data/Table.vue b/src/runtime/components/data/Table.vue
index 4e763859..b7688315 100644
--- a/src/runtime/components/data/Table.vue
+++ b/src/runtime/components/data/Table.vue
@@ -77,7 +77,7 @@ import appConfig from '#build/app.config'
// const appConfig = useAppConfig()
-function defaultComparator(a: T, z: T): boolean {
+function defaultComparator (a: T, z: T): boolean {
return a === z
}
diff --git a/src/runtime/components/forms/Range.vue b/src/runtime/components/forms/Range.vue
new file mode 100644
index 00000000..d43f2202
--- /dev/null
+++ b/src/runtime/components/forms/Range.vue
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+