@revojs/ui 0.3.9 → 0.3.11

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.
@@ -1,5 +1,6 @@
1
1
  import type { IconComponent } from "./icon";
2
2
  import type { StackProps } from "./stack";
3
+ export type CollapsibleSize = "md" | "sm";
3
4
  export interface CollapsibleProps {
4
5
  modelValue?: boolean;
5
6
  label: string;
@@ -8,4 +9,5 @@ export interface CollapsibleProps {
8
9
  disabled?: boolean;
9
10
  bodyPadding?: StackProps["padding"];
10
11
  bodyGap?: StackProps["gap"];
12
+ size?: CollapsibleSize;
11
13
  }
@@ -0,0 +1,8 @@
1
+ import type { StackProps } from "./stack";
2
+ export interface SettingProps extends StackProps {
3
+ label: string;
4
+ description?: string;
5
+ error?: string;
6
+ for?: string;
7
+ disabled?: boolean;
8
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -32,6 +32,7 @@ export type * from "./components/rating";
32
32
  export type * from "./components/roving-focus";
33
33
  export type * from "./components/select";
34
34
  export type * from "./components/separator";
35
+ export type * from "./components/setting";
35
36
  export type * from "./components/sheet";
36
37
  export type * from "./components/shell";
37
38
  export type * from "./components/stack";
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <Stack
3
+ v-bind="rootAttributes"
3
4
  is="label"
4
5
  direction="horizontal"
5
6
  align="start"
@@ -9,6 +10,7 @@
9
10
  >
10
11
  <input
11
12
  ref="input"
13
+ v-bind="controlAttributes"
12
14
  class="peer sr-only"
13
15
  type="checkbox"
14
16
  :checked="modelValue"
@@ -51,6 +53,7 @@
51
53
  import { computed, useTemplateRef, watchEffect } from "vue";
52
54
  import type { CheckboxProps } from "../../components/checkbox";
53
55
  import type { ControlInteraction } from "../../components/control.ts";
56
+ import { useControlAttributes } from "../utilities/use-control-attributes";
54
57
  import Stack from "./stack.vue";
55
58
 
56
59
  const {
@@ -63,6 +66,10 @@ const {
63
66
  disabled = false,
64
67
  } = defineProps<CheckboxProps>();
65
68
 
69
+ defineOptions({ inheritAttrs: false });
70
+
71
+ const { rootAttributes, controlAttributes } = useControlAttributes();
72
+
66
73
  defineEmits<{
67
74
  "update:modelValue": [value: boolean];
68
75
  }>();
@@ -1,38 +1,59 @@
1
1
  <template>
2
- <details
3
- :name="name"
4
- :open="isOpen"
5
- class="group/collapsible w-full rounded-ui"
6
- :data-state="isOpen ? 'open' : 'closed'"
7
- :data-disabled="disabled ? '' : undefined"
8
- @toggle="handleToggle"
9
- >
10
- <summary
11
- class="flex cursor-pointer list-none items-center gap-1 rounded-ui p-3 text-sm font-medium outline-ring select-none hover:bg-ghost-hover active:bg-ghost-active focus-visible:outline-2 focus-visible:outline-offset-[-2px] [&::-webkit-details-marker]:hidden"
12
- :class="disabled ? 'cursor-not-allowed opacity-50 hover:bg-transparent active:bg-transparent' : ''"
13
- :tabindex="disabled ? -1 : undefined"
14
- :aria-disabled="disabled || undefined"
15
- @click="disabled && $event.preventDefault()"
2
+ <div class="relative w-full">
3
+ <details
4
+ :name="name"
5
+ :open="isOpen"
6
+ class="group/collapsible w-full rounded-ui"
7
+ :data-state="isOpen ? 'open' : 'closed'"
8
+ :data-disabled="disabled ? '' : undefined"
9
+ @toggle="handleToggle"
16
10
  >
17
- <Icon v-if="iconPrefix" :is="iconPrefix" :size="20" />
11
+ <summary
12
+ class="flex cursor-pointer list-none items-center gap-1 rounded-ui outline-ring select-none focus-visible:outline-2 focus-visible:outline-offset-[-2px] [&::-webkit-details-marker]:hidden"
13
+ :class="[
14
+ sizes[size],
15
+ $slots.actions ? 'pr-10' : '',
16
+ disabled ? 'cursor-not-allowed opacity-50 hover:bg-transparent active:bg-transparent' : '',
17
+ ]"
18
+ :tabindex="disabled ? -1 : undefined"
19
+ :aria-disabled="disabled || undefined"
20
+ @click="disabled && $event.preventDefault()"
21
+ >
22
+ <Icon v-if="iconPrefix" :is="iconPrefix" :size="20" />
18
23
 
19
- <span class="min-w-0 flex-1 truncate px-1">{{ label }}</span>
24
+ <span class="min-w-0 truncate px-1" :class="size === 'md' ? 'flex-1' : ''">{{ label }}</span>
20
25
 
21
- <Icon :is="ArrowDownIcon" :size="20" class="shrink-0 group-open/collapsible:rotate-180" />
22
- </summary>
26
+ <Icon
27
+ :is="ArrowDownIcon"
28
+ :size="size === 'md' ? 20 : 16"
29
+ class="shrink-0 group-open/collapsible:rotate-180"
30
+ />
31
+ </summary>
23
32
 
24
- <Stack :padding="bodyPadding">
25
- <Stack :gap="bodyGap" class="px-1">
26
- <slot />
33
+ <Stack :padding="bodyPadding">
34
+ <Stack :gap="bodyGap" :class="size === 'md' ? 'px-1' : ''">
35
+ <slot />
36
+ </Stack>
27
37
  </Stack>
38
+ </details>
39
+
40
+ <Stack
41
+ v-if="$slots.actions"
42
+ direction="horizontal"
43
+ align="center"
44
+ gap="0"
45
+ class="absolute top-0 right-1"
46
+ :class="actionHeights[size]"
47
+ >
48
+ <slot name="actions" />
28
49
  </Stack>
29
- </details>
50
+ </div>
30
51
  </template>
31
52
 
32
53
  <script setup lang="ts">
33
54
  import ArrowDownIcon from "~icons/hugeicons/arrow-down-01";
34
55
  import { ref, watch } from "vue";
35
- import type { CollapsibleProps } from "../../components/collapsible";
56
+ import type { CollapsibleProps, CollapsibleSize } from "../../components/collapsible";
36
57
  import Icon from "./icon.vue";
37
58
  import Stack from "./stack.vue";
38
59
 
@@ -44,6 +65,7 @@ const {
44
65
  disabled = false,
45
66
  bodyPadding = "3",
46
67
  bodyGap = "3",
68
+ size = "md",
47
69
  } = defineProps<CollapsibleProps>();
48
70
 
49
71
  const emit = defineEmits<{
@@ -52,6 +74,16 @@ const emit = defineEmits<{
52
74
 
53
75
  const isOpen = ref(modelValue ?? false);
54
76
 
77
+ const actionHeights: Record<CollapsibleSize, string> = {
78
+ md: "h-11",
79
+ sm: "h-8",
80
+ };
81
+
82
+ const sizes: Record<CollapsibleSize, string> = {
83
+ md: "p-3 text-sm font-medium hover:bg-ghost-hover active:bg-ghost-active",
84
+ sm: "p-2 text-xs font-normal text-muted-foreground hover:text-foreground",
85
+ };
86
+
55
87
  function handleToggle(event: Event) {
56
88
  const value = (event.currentTarget as HTMLDetailsElement).open;
57
89
 
@@ -1,5 +1,31 @@
1
1
  <template>
2
+ <div v-if="$slots.actions" class="group/navigate relative">
3
+ <Button
4
+ is="a"
5
+ :href="href"
6
+ font="normal"
7
+ layout="left"
8
+ :size="size"
9
+ :variant="active ? 'secondary' : 'ghost'"
10
+ :icon-prefix="iconPrefix"
11
+ :icon-suffix="iconSuffix"
12
+ :label="label"
13
+ :aria-current="active ? 'page' : undefined"
14
+ class="w-full pr-10"
15
+ :class="
16
+ active
17
+ ? 'group-hover/navigate:bg-secondary-hover group-has-[[data-state=open]]/navigate:bg-secondary-hover'
18
+ : 'group-hover/navigate:bg-ghost-hover group-has-[[data-state=open]]/navigate:bg-ghost-hover'
19
+ "
20
+ />
21
+
22
+ <Stack direction="horizontal" align="center" gap="0" class="absolute inset-y-0 right-1">
23
+ <slot name="actions" />
24
+ </Stack>
25
+ </div>
26
+
2
27
  <Button
28
+ v-else
3
29
  is="a"
4
30
  :href="href"
5
31
  font="normal"
@@ -16,6 +42,7 @@
16
42
  <script setup lang="ts">
17
43
  import type { NavigateProps } from "../../components/navigate";
18
44
  import Button from "./button.vue";
45
+ import Stack from "./stack.vue";
19
46
 
20
47
  const { href, label, iconPrefix, iconSuffix, active = false, size = "md" } = defineProps<NavigateProps>();
21
48
  </script>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <Stack
3
+ :padding="padding"
4
+ :gap="gap"
5
+ :direction="direction"
6
+ :align="align"
7
+ :justify="justify"
8
+ :wrap="wrap"
9
+ class="min-w-0 text-sm"
10
+ :class="disabled ? 'opacity-50' : ''"
11
+ >
12
+ <Stack gap="0" class="min-w-32 flex-1">
13
+ <component :is="controlId ? 'label' : 'span'" :id="`${id}-label`" :for="controlId" class="font-normal">
14
+ {{ label }}
15
+ </component>
16
+
17
+ <p v-if="error" :id="`${id}-error`" role="alert" class="text-destructive">{{ error }}</p>
18
+ <p v-else-if="description" :id="`${id}-description`" class="opacity-60">{{ description }}</p>
19
+ </Stack>
20
+
21
+ <Stack v-if="$slots.default" direction="horizontal" align="center" gap="1" class="shrink-0">
22
+ <slot :control="controlAttributes" />
23
+ </Stack>
24
+ </Stack>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { computed, useId } from "vue";
29
+ import type { SettingProps } from "../../components/setting";
30
+ import Stack from "./stack.vue";
31
+
32
+ const {
33
+ label,
34
+ description,
35
+ error,
36
+ for: controlId,
37
+ disabled = false,
38
+ padding = "0",
39
+ gap = "5",
40
+ direction = "horizontal",
41
+ align = "center",
42
+ justify = "between",
43
+ wrap = true,
44
+ } = defineProps<SettingProps>();
45
+
46
+ const id = `setting-${useId()}`;
47
+
48
+ const controlAttributes = computed(() => ({
49
+ id: controlId,
50
+ disabled,
51
+ "aria-labelledby": controlId ? undefined : `${id}-label`,
52
+ "aria-describedby": error ? `${id}-error` : description ? `${id}-description` : undefined,
53
+ "aria-invalid": error ? true : undefined,
54
+ }));
55
+ </script>
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <Stack
3
+ v-bind="rootAttributes"
3
4
  is="label"
4
5
  direction="horizontal"
5
6
  align="start"
@@ -10,6 +11,7 @@
10
11
  <input v-if="name" type="hidden" :name="name" :value="modelValue ? 'on' : 'off'" />
11
12
 
12
13
  <button
14
+ v-bind="controlAttributes"
13
15
  class="relative flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-ui p-0.5 outline-ring focus-visible:outline-2 focus-visible:outline-offset-2 disabled:cursor-not-allowed"
14
16
  :class="[
15
17
  variants[state],
@@ -42,10 +44,15 @@
42
44
  import { computed } from "vue";
43
45
  import type { ControlInteraction } from "../../components/control.ts";
44
46
  import type { SwitchProps, SwitchState } from "../../components/switch";
47
+ import { useControlAttributes } from "../utilities/use-control-attributes";
45
48
  import Stack from "./stack.vue";
46
49
 
47
50
  const { modelValue = false, label, description, name, disabled = false } = defineProps<SwitchProps>();
48
51
 
52
+ defineOptions({ inheritAttrs: false });
53
+
54
+ const { rootAttributes, controlAttributes } = useControlAttributes();
55
+
49
56
  defineEmits<{
50
57
  "update:modelValue": [value: boolean];
51
58
  }>();
@@ -36,6 +36,7 @@ export { default as Range } from "./components/range.vue";
36
36
  export { default as Rating } from "./components/rating.vue";
37
37
  export { default as Select } from "./components/select.vue";
38
38
  export { default as Separator } from "./components/separator.vue";
39
+ export { default as Setting } from "./components/setting.vue";
39
40
  export { default as Sheet } from "./components/sheet.vue";
40
41
  export { default as Shell } from "./components/shell.vue";
41
42
  export { default as Stack } from "./components/stack.vue";
package/dist/vue/index.js CHANGED
@@ -48,6 +48,7 @@ import Range from "./components/range.vue";
48
48
  import Rating from "./components/rating.vue";
49
49
  import Select from "./components/select.vue";
50
50
  import Separator from "./components/separator.vue";
51
+ import Setting from "./components/setting.vue";
51
52
  import Sheet from "./components/sheet.vue";
52
53
  import Shell from "./components/shell.vue";
53
54
  import Stack from "./components/stack.vue";
@@ -61,4 +62,4 @@ import ToggleGroup from "./components/toggle-group.vue";
61
62
  import Toolbar from "./components/toolbar.vue";
62
63
  import Tooltip from "./components/tooltip.vue";
63
64
  import Upload from "./components/upload.vue";
64
- export { Accordion, Badge, Breadcrumb, Button, Card, Checkbox, Collapsible, Collection, ConfirmDialog, Container, ContextMenu, Counter, Dialog, Entry, Field, Heading, Icon, Input, Link, Markdown, Menu, MenuCheckboxItem, MenuGroup, MenuItem, MenuLayer, MenuRadioGroup, MenuRadioItem, Navigate, Notification, Pagination, Popover, Progress, Radio, RadioGroup, Range, Rating, Select, Separator, Sheet, Shell, Stack, Stepper, Switch, Tabs, TagsInput, Textarea, ToastRegion, ToggleGroup, Toolbar, Tooltip, Upload, defaultUiLabels, germanUiLabels, isTypeaheadKey, menuCloseKey, menuItemSelector, menuRadioKey, menuSizeKey, provideUiLabels, tooltipState, uiLabelsKey, useAnchor, useConfirm, useControlAttributes, useMenuNavigation, useModalDialog, useRovingFocus, useScrollLock, useToast, useTypeahead, useUiLabels };
65
+ export { Accordion, Badge, Breadcrumb, Button, Card, Checkbox, Collapsible, Collection, ConfirmDialog, Container, ContextMenu, Counter, Dialog, Entry, Field, Heading, Icon, Input, Link, Markdown, Menu, MenuCheckboxItem, MenuGroup, MenuItem, MenuLayer, MenuRadioGroup, MenuRadioItem, Navigate, Notification, Pagination, Popover, Progress, Radio, RadioGroup, Range, Rating, Select, Separator, Setting, Sheet, Shell, Stack, Stepper, Switch, Tabs, TagsInput, Textarea, ToastRegion, ToggleGroup, Toolbar, Tooltip, Upload, defaultUiLabels, germanUiLabels, isTypeaheadKey, menuCloseKey, menuItemSelector, menuRadioKey, menuSizeKey, provideUiLabels, tooltipState, uiLabelsKey, useAnchor, useConfirm, useControlAttributes, useMenuNavigation, useModalDialog, useRovingFocus, useScrollLock, useToast, useTypeahead, useUiLabels };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revojs/ui",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,14 +35,14 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@iconify-json/hugeicons": "^1.2.35",
38
- "@revojs/client": "0.3.9",
38
+ "@revojs/client": "0.3.11",
39
39
  "@tailwindcss/vite": "^4.3.3",
40
- "revojs": "0.3.9",
40
+ "revojs": "0.3.11",
41
41
  "tailwindcss": "^4.3.3",
42
42
  "unplugin-icons": "^24.0.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@revojs/tsconfig": "0.3.9",
45
+ "@revojs/tsconfig": "0.3.11",
46
46
  "@vitejs/plugin-vue": "^6.0.9"
47
47
  },
48
48
  "optionalDependencies": {