@sewadah/selaras 0.9.0 → 0.10.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.
Files changed (66) hide show
  1. package/README.md +11 -0
  2. package/dist/agent/catalog.json +1 -1
  3. package/dist/module.json +1 -1
  4. package/dist/runtime/components/Checkbox.d.vue.ts +6 -4
  5. package/dist/runtime/components/Checkbox.vue +30 -22
  6. package/dist/runtime/components/Checkbox.vue.d.ts +6 -4
  7. package/dist/runtime/components/DatePicker.d.vue.ts +27 -27
  8. package/dist/runtime/components/DatePicker.vue +58 -99
  9. package/dist/runtime/components/DatePicker.vue.d.ts +27 -27
  10. package/dist/runtime/components/Editable.d.vue.ts +91 -0
  11. package/dist/runtime/components/Editable.vue +257 -0
  12. package/dist/runtime/components/Editable.vue.d.ts +91 -0
  13. package/dist/runtime/components/Input.vue +21 -22
  14. package/dist/runtime/components/Textarea.vue +20 -23
  15. package/dist/runtime/components/Toolbar.d.vue.ts +25 -0
  16. package/dist/runtime/components/Toolbar.vue +35 -0
  17. package/dist/runtime/components/Toolbar.vue.d.ts +25 -0
  18. package/dist/runtime/components/ToolbarButton.d.vue.ts +20 -0
  19. package/dist/runtime/components/ToolbarButton.vue +46 -0
  20. package/dist/runtime/components/ToolbarButton.vue.d.ts +20 -0
  21. package/dist/runtime/components/ToolbarSeparator.d.vue.ts +10 -0
  22. package/dist/runtime/components/ToolbarSeparator.vue +22 -0
  23. package/dist/runtime/components/ToolbarSeparator.vue.d.ts +10 -0
  24. package/dist/runtime/components/ToolbarToggleGroup.d.vue.ts +37 -0
  25. package/dist/runtime/components/ToolbarToggleGroup.vue +44 -0
  26. package/dist/runtime/components/ToolbarToggleGroup.vue.d.ts +37 -0
  27. package/dist/runtime/internal/ComboboxSelectBase.vue +41 -50
  28. package/dist/runtime/internal/FieldClearButton.d.vue.ts +21 -0
  29. package/dist/runtime/internal/FieldClearButton.vue +30 -0
  30. package/dist/runtime/internal/FieldClearButton.vue.d.ts +21 -0
  31. package/dist/runtime/internal/ListboxOption.d.vue.ts +2 -1
  32. package/dist/runtime/internal/ListboxOption.vue +3 -2
  33. package/dist/runtime/internal/ListboxOption.vue.d.ts +2 -1
  34. package/dist/runtime/theme/date-picker.d.ts +27 -0
  35. package/dist/runtime/theme/date-picker.js +6 -3
  36. package/dist/runtime/theme/editable.d.ts +155 -0
  37. package/dist/runtime/theme/editable.js +25 -0
  38. package/dist/runtime/theme/field-clear-button.d.ts +56 -0
  39. package/dist/runtime/theme/field-clear-button.js +15 -0
  40. package/dist/runtime/theme/input.d.ts +0 -9
  41. package/dist/runtime/theme/input.js +5 -12
  42. package/dist/runtime/theme/listbox.js +1 -1
  43. package/dist/runtime/theme/select.d.ts +9 -0
  44. package/dist/runtime/theme/select.js +11 -10
  45. package/dist/runtime/theme/textarea.d.ts +0 -9
  46. package/dist/runtime/theme/textarea.js +4 -4
  47. package/dist/runtime/theme/toolbar-button.d.ts +65 -0
  48. package/dist/runtime/theme/toolbar-button.js +21 -0
  49. package/dist/runtime/theme/toolbar-separator.d.ts +35 -0
  50. package/dist/runtime/theme/toolbar-separator.js +8 -0
  51. package/dist/runtime/theme/toolbar-toggle-group.d.ts +74 -0
  52. package/dist/runtime/theme/toolbar-toggle-group.js +13 -0
  53. package/dist/runtime/theme/toolbar.d.ts +35 -0
  54. package/dist/runtime/theme/toolbar.js +11 -0
  55. package/dist/runtime/theme-config.d.ts +36 -0
  56. package/dist/runtime/types/index.d.ts +5 -0
  57. package/dist/runtime/utils/field-clear.d.ts +9 -0
  58. package/dist/runtime/utils/field-clear.js +7 -0
  59. package/dist/runtime/utils/icons.d.ts +1 -0
  60. package/dist/runtime/utils/icons.js +1 -0
  61. package/dist/runtime/utils/messages.d.ts +4 -0
  62. package/dist/runtime/utils/messages.js +4 -0
  63. package/dist/runtime/utils/toolbar.d.ts +9 -0
  64. package/dist/runtime/utils/toolbar.js +1 -0
  65. package/package.json +9 -2
  66. package/skills/selaras/SKILL.md +4 -0
@@ -1,14 +1,13 @@
1
1
  <script setup>
2
- import { computed, mergeProps, nextTick, onMounted, ref, watch } from "vue";
2
+ import { computed, mergeProps, nextTick, onMounted, ref, useAttrs, watch } from "vue";
3
3
  import { useFormField } from "../composables/use-form-field";
4
- import { useIcons } from "../composables/use-icons";
5
- import { useMessages } from "../composables/use-messages";
4
+ import FieldClearButton from "../internal/FieldClearButton.vue";
6
5
  import { textareaTheme } from "../theme/textarea";
7
6
  import { useFieldAdornments } from "../utils/field-adornments";
7
+ import { canClearField, fieldClearWidths, isFieldReadonly } from "../utils/field-clear";
8
8
  import { isNativeInputA11yAttr, isNativeInputAttr } from "../utils/native-input";
9
9
  import { resolveRegisteredColorRole } from "../utils/registered-colors";
10
10
  import { resolveSlot, useComponentTheme, useFallthroughAttrs, useRootProps } from "../utils/ui";
11
- import Button from "./Button.vue";
12
11
  import Icon from "./Icon.vue";
13
12
  defineOptions({ inheritAttrs: false });
14
13
  const props = defineProps({
@@ -32,21 +31,25 @@ const emit = defineEmits(["update:modelValue"]);
32
31
  const slots = defineSlots();
33
32
  const { leading, trailing, padding, clearOffset } = useFieldAdornments();
34
33
  const field = useFormField();
34
+ const attrs = useAttrs();
35
+ const textareaRef = ref();
35
36
  const effectivePlaceholder = computed(() => props.placeholder || (field?.floatingLabel.value ? " " : void 0));
36
37
  const textareaId = computed(() => props.id ?? field?.id);
37
38
  const textareaInvalid = computed(() => props.invalid || (field?.invalid.value ?? false));
38
39
  const describedBy = computed(() => field?.describedBy.value);
39
- const hasValue = computed(() => props.modelValue !== void 0 && props.modelValue !== "");
40
- const showClear = computed(() => !!props.clearable && !props.disabled && hasValue.value);
41
- function clear() {
40
+ const hasValue = computed(() => props.modelValue != null && props.modelValue !== "");
41
+ const showClear = computed(() => canClearField(props.clearable, hasValue.value, props.disabled, isFieldReadonly(attrs.readonly)));
42
+ async function clear() {
43
+ if (!showClear.value)
44
+ return;
42
45
  emit("update:modelValue", "");
46
+ await nextTick();
47
+ textareaRef.value?.focus();
43
48
  }
44
49
  const effectiveSize = computed(() => props.size ?? field?.size ?? "md");
45
- const clearSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
46
- const adornmentScope = computed(() => ({ disabled: !!props.disabled, size: effectiveSize.value, buttonSize: clearSize.value }));
47
- const clearWidth = computed(() => ({ sm: "1.75rem", md: "2.25rem", lg: "2.5rem" })[effectiveSize.value]);
48
- const icons = useIcons();
49
- const messages = useMessages();
50
+ const adornmentButtonSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
51
+ const adornmentScope = computed(() => ({ disabled: !!props.disabled, size: effectiveSize.value, buttonSize: adornmentButtonSize.value }));
52
+ const clearWidth = computed(() => fieldClearWidths[effectiveSize.value]);
50
53
  const theme = useComponentTheme("textarea", textareaTheme);
51
54
  const effectiveColor = computed(() => resolveRegisteredColorRole(props.color ?? "primary", "primary"));
52
55
  const ui = computed(() => theme.value({
@@ -61,7 +64,6 @@ const isTextareaAttr = (key) => isNativeInputAttr(key) || isNativeInputA11yAttr(
61
64
  const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root, { exclude: isTextareaAttr });
62
65
  const nativeTextareaAttrs = useFallthroughAttrs(isTextareaAttr);
63
66
  const baseProps = computed(() => mergeProps(resolveSlot(ui.value.base, props.ui?.base), nativeTextareaAttrs.value));
64
- const textareaRef = ref();
65
67
  async function resize() {
66
68
  if (!props.autoresize || !textareaRef.value)
67
69
  return;
@@ -110,21 +112,16 @@ function clearProps() {
110
112
  @input="$emit('update:modelValue', $event.target.value);
111
113
  resize()"
112
114
  />
113
- <Button
115
+ <FieldClearButton
114
116
  v-if="showClear"
115
- :size="clearSize"
116
- variant="text"
117
- color="neutral"
118
- :aria-label="messages.clear"
117
+ :size="effectiveSize"
119
118
  v-bind="clearProps()"
120
119
  @click="clear"
121
120
  >
122
- <template #icon="{ class: iconClass }">
123
- <slot name="clear-icon">
124
- <Icon :name="icons.close" :class="iconClass" />
125
- </slot>
121
+ <template v-if="slots['clear-icon']" #default>
122
+ <slot name="clear-icon" />
126
123
  </template>
127
- </Button>
124
+ </FieldClearButton>
128
125
  <Icon v-else-if="trailingIcon && !slots.trailing" :name="trailingIcon" v-bind="resolveSlot(ui.trailingIcon, props.ui?.trailingIcon)" />
129
126
  <fieldset v-if="slots.trailing" ref="trailing" :disabled="disabled" :inert="disabled || void 0" v-bind="resolveSlot(ui.trailing, props.ui?.trailing)">
130
127
  <slot name="trailing" v-bind="adornmentScope" />
@@ -0,0 +1,25 @@
1
+ import type { ToolbarThemeSlots } from '../theme/toolbar.js';
2
+ import type { ColorRole } from '../utils/color-registry.js';
3
+ import type { UiProp } from '../utils/ui.js';
4
+ type __VLS_Slots = ToolbarSlots;
5
+ export interface ToolbarProps {
6
+ orientation?: 'horizontal' | 'vertical';
7
+ size?: 'sm' | 'md' | 'lg';
8
+ color?: ColorRole;
9
+ disabled?: boolean;
10
+ loop?: boolean;
11
+ dir?: 'ltr' | 'rtl';
12
+ ui?: UiProp<ToolbarThemeSlots>;
13
+ }
14
+ export interface ToolbarSlots {
15
+ default?: () => any;
16
+ }
17
+ declare const __VLS_base: import("vue").DefineComponent<ToolbarProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ToolbarProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
19
+ declare const _default: typeof __VLS_export;
20
+ export default _default;
21
+ type __VLS_WithSlots<T, S> = T & {
22
+ new (): {
23
+ $slots: S;
24
+ };
25
+ };
@@ -0,0 +1,35 @@
1
+ <script setup>
2
+ import { ToolbarRoot } from "reka-ui";
3
+ import { computed, provide } from "vue";
4
+ import { toolbarTheme } from "../theme/toolbar";
5
+ import { TOOLBAR_CONTEXT } from "../utils/toolbar";
6
+ import { useComponentTheme, useRootProps, useThemeProps } from "../utils/ui";
7
+ defineOptions({ inheritAttrs: false });
8
+ const props = defineProps({
9
+ orientation: { type: String, required: false, default: "horizontal" },
10
+ size: { type: String, required: false },
11
+ color: { type: null, required: false },
12
+ disabled: { type: Boolean, required: false },
13
+ loop: { type: Boolean, required: false, default: true },
14
+ dir: { type: String, required: false },
15
+ ui: { type: Object, required: false }
16
+ });
17
+ defineSlots();
18
+ const defaults = useThemeProps("toolbar");
19
+ const context = computed(() => ({
20
+ size: props.size ?? defaults.value.size ?? "sm",
21
+ color: props.color ?? defaults.value.color ?? "primary",
22
+ disabled: !!props.disabled,
23
+ orientation: props.orientation
24
+ }));
25
+ provide(TOOLBAR_CONTEXT, context);
26
+ const theme = useComponentTheme("toolbar", toolbarTheme);
27
+ const ui = computed(() => theme.value({ orientation: props.orientation }));
28
+ const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root);
29
+ </script>
30
+
31
+ <template>
32
+ <ToolbarRoot :orientation="orientation" :dir="dir" :loop="loop" :aria-disabled="disabled || void 0" v-bind="rootProps">
33
+ <slot />
34
+ </ToolbarRoot>
35
+ </template>
@@ -0,0 +1,25 @@
1
+ import type { ToolbarThemeSlots } from '../theme/toolbar.js';
2
+ import type { ColorRole } from '../utils/color-registry.js';
3
+ import type { UiProp } from '../utils/ui.js';
4
+ type __VLS_Slots = ToolbarSlots;
5
+ export interface ToolbarProps {
6
+ orientation?: 'horizontal' | 'vertical';
7
+ size?: 'sm' | 'md' | 'lg';
8
+ color?: ColorRole;
9
+ disabled?: boolean;
10
+ loop?: boolean;
11
+ dir?: 'ltr' | 'rtl';
12
+ ui?: UiProp<ToolbarThemeSlots>;
13
+ }
14
+ export interface ToolbarSlots {
15
+ default?: () => any;
16
+ }
17
+ declare const __VLS_base: import("vue").DefineComponent<ToolbarProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ToolbarProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
19
+ declare const _default: typeof __VLS_export;
20
+ export default _default;
21
+ type __VLS_WithSlots<T, S> = T & {
22
+ new (): {
23
+ $slots: S;
24
+ };
25
+ };
@@ -0,0 +1,20 @@
1
+ import type { ButtonProps } from './Button.vue.js';
2
+ type __VLS_Slots = ToolbarButtonSlots;
3
+ export interface ToolbarButtonProps extends ButtonProps {
4
+ /** Formatting state owned by the editor; omitted for ordinary actions. */
5
+ pressed?: boolean;
6
+ /** Composes a custom trigger into the toolbar's keyboard navigation. */
7
+ asChild?: boolean;
8
+ }
9
+ export interface ToolbarButtonSlots {
10
+ default?: () => any;
11
+ }
12
+ declare const __VLS_base: import("vue").DefineComponent<ToolbarButtonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ToolbarButtonProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
14
+ declare const _default: typeof __VLS_export;
15
+ export default _default;
16
+ type __VLS_WithSlots<T, S> = T & {
17
+ new (): {
18
+ $slots: S;
19
+ };
20
+ };
@@ -0,0 +1,46 @@
1
+ <script setup>
2
+ import { ToolbarButton } from "reka-ui";
3
+ import { computed, inject } from "vue";
4
+ import { toolbarButtonTheme } from "../theme/toolbar-button";
5
+ import { TOOLBAR_CONTEXT } from "../utils/toolbar";
6
+ import { resolveSlot, useComponentTheme, useRootProps } from "../utils/ui";
7
+ import Button from "./Button.vue";
8
+ defineOptions({ inheritAttrs: false });
9
+ const props = defineProps({
10
+ pressed: { type: Boolean, required: false, default: void 0 },
11
+ asChild: { type: Boolean, required: false },
12
+ as: { type: null, required: false },
13
+ to: { type: String, required: false },
14
+ type: { type: String, required: false },
15
+ color: { type: null, required: false },
16
+ variant: { type: null, required: false },
17
+ size: { type: null, required: false },
18
+ block: { type: Boolean, required: false },
19
+ disabled: { type: Boolean, required: false },
20
+ loading: { type: Boolean, required: false },
21
+ raised: { type: Boolean, required: false },
22
+ icon: { type: String, required: false },
23
+ trailingIcon: { type: String, required: false },
24
+ square: { type: Boolean, required: false, default: void 0 },
25
+ ui: { type: Object, required: false }
26
+ });
27
+ defineSlots();
28
+ const toolbar = inject(TOOLBAR_CONTEXT, void 0);
29
+ const disabled = computed(() => props.disabled || toolbar?.value.disabled);
30
+ const size = computed(() => props.size ?? toolbar?.value.size ?? "sm");
31
+ const color = computed(() => props.color ?? toolbar?.value.color ?? "primary");
32
+ const theme = useComponentTheme("toolbarButton", toolbarButtonTheme);
33
+ const ui = computed(() => theme.value({ size: size.value, variant: props.variant ?? "ghost" }));
34
+ const rootProps = useRootProps(() => ui.value.base, () => props.ui?.base);
35
+ </script>
36
+
37
+ <template>
38
+ <ToolbarButton as-child :disabled="disabled" :aria-pressed="pressed" :data-state="pressed === void 0 ? void 0 : pressed ? 'on' : 'off'" v-bind="rootProps">
39
+ <slot v-if="asChild" />
40
+ <Button v-else v-bind="as ? { as } : {}" :to="to" :type="type" :disabled="disabled" :size="size" :color="color" :variant="variant ?? 'ghost'" :icon="icon" :trailing-icon="trailingIcon" :square="square" :loading="loading" :raised="raised" :block="block" :ui="{ leadingIcon: resolveSlot(ui.leadingIcon, props.ui?.leadingIcon), trailingIcon: resolveSlot(ui.trailingIcon, props.ui?.trailingIcon) }">
41
+ <template v-if="$slots.default" #default>
42
+ <slot />
43
+ </template>
44
+ </Button>
45
+ </ToolbarButton>
46
+ </template>
@@ -0,0 +1,20 @@
1
+ import type { ButtonProps } from './Button.vue.js';
2
+ type __VLS_Slots = ToolbarButtonSlots;
3
+ export interface ToolbarButtonProps extends ButtonProps {
4
+ /** Formatting state owned by the editor; omitted for ordinary actions. */
5
+ pressed?: boolean;
6
+ /** Composes a custom trigger into the toolbar's keyboard navigation. */
7
+ asChild?: boolean;
8
+ }
9
+ export interface ToolbarButtonSlots {
10
+ default?: () => any;
11
+ }
12
+ declare const __VLS_base: import("vue").DefineComponent<ToolbarButtonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ToolbarButtonProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
14
+ declare const _default: typeof __VLS_export;
15
+ export default _default;
16
+ type __VLS_WithSlots<T, S> = T & {
17
+ new (): {
18
+ $slots: S;
19
+ };
20
+ };
@@ -0,0 +1,10 @@
1
+ import type { ToolbarSeparatorThemeSlots } from '../theme/toolbar-separator.js';
2
+ import type { UiProp } from '../utils/ui.js';
3
+ export interface ToolbarSeparatorProps {
4
+ orientation?: 'horizontal' | 'vertical';
5
+ decorative?: boolean;
6
+ ui?: UiProp<ToolbarSeparatorThemeSlots>;
7
+ }
8
+ declare const __VLS_export: import("vue").DefineComponent<ToolbarSeparatorProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ToolbarSeparatorProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;
@@ -0,0 +1,22 @@
1
+ <script setup>
2
+ import { Separator } from "reka-ui";
3
+ import { computed, inject } from "vue";
4
+ import { toolbarSeparatorTheme } from "../theme/toolbar-separator";
5
+ import { TOOLBAR_CONTEXT } from "../utils/toolbar";
6
+ import { useComponentTheme, useRootProps } from "../utils/ui";
7
+ defineOptions({ inheritAttrs: false });
8
+ const props = defineProps({
9
+ orientation: { type: String, required: false },
10
+ decorative: { type: Boolean, required: false, default: true },
11
+ ui: { type: Object, required: false }
12
+ });
13
+ const toolbar = inject(TOOLBAR_CONTEXT, void 0);
14
+ const orientation = computed(() => props.orientation ?? (toolbar?.value.orientation === "vertical" ? "horizontal" : "vertical"));
15
+ const theme = useComponentTheme("toolbarSeparator", toolbarSeparatorTheme);
16
+ const ui = computed(() => theme.value({ orientation: orientation.value }));
17
+ const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root);
18
+ </script>
19
+
20
+ <template>
21
+ <Separator :orientation="orientation" :decorative="decorative" v-bind="rootProps" />
22
+ </template>
@@ -0,0 +1,10 @@
1
+ import type { ToolbarSeparatorThemeSlots } from '../theme/toolbar-separator.js';
2
+ import type { UiProp } from '../utils/ui.js';
3
+ export interface ToolbarSeparatorProps {
4
+ orientation?: 'horizontal' | 'vertical';
5
+ decorative?: boolean;
6
+ ui?: UiProp<ToolbarSeparatorThemeSlots>;
7
+ }
8
+ declare const __VLS_export: import("vue").DefineComponent<ToolbarSeparatorProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ToolbarSeparatorProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;
@@ -0,0 +1,37 @@
1
+ import type { ToolbarToggleGroupThemeSlots } from '../theme/toolbar-toggle-group.js';
2
+ import type { ColorRole } from '../utils/color-registry.js';
3
+ import type { UiProp } from '../utils/ui.js';
4
+ import type { ToggleGroupItemDef } from './ToggleGroup.vue.js';
5
+ type __VLS_Slots = ToolbarToggleGroupSlots;
6
+ export interface ToolbarToggleGroupProps {
7
+ items: (string | ToggleGroupItemDef)[];
8
+ type?: 'single' | 'multiple';
9
+ modelValue?: string | string[];
10
+ defaultValue?: string | string[];
11
+ disabled?: boolean;
12
+ iconOnly?: boolean;
13
+ size?: 'sm' | 'md' | 'lg';
14
+ color?: ColorRole;
15
+ ui?: UiProp<ToolbarToggleGroupThemeSlots>;
16
+ }
17
+ export interface ToolbarToggleGroupEmits {
18
+ 'update:modelValue': [value: string | string[]];
19
+ }
20
+ export interface ToolbarToggleGroupSlots {
21
+ item?: (props: {
22
+ item: ToggleGroupItemDef;
23
+ }) => any;
24
+ }
25
+ declare const __VLS_base: import("vue").DefineComponent<ToolbarToggleGroupProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
26
+ "update:modelValue": (value: string | string[]) => any;
27
+ }, string, import("vue").PublicProps, Readonly<ToolbarToggleGroupProps> & Readonly<{
28
+ "onUpdate:modelValue"?: ((value: string | string[]) => any) | undefined;
29
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
31
+ declare const _default: typeof __VLS_export;
32
+ export default _default;
33
+ type __VLS_WithSlots<T, S> = T & {
34
+ new (): {
35
+ $slots: S;
36
+ };
37
+ };
@@ -0,0 +1,44 @@
1
+ <script setup>
2
+ import { ToolbarToggleGroup, ToolbarToggleItem } from "reka-ui";
3
+ import { computed, inject } from "vue";
4
+ import { toolbarToggleGroupTheme } from "../theme/toolbar-toggle-group";
5
+ import { TOOLBAR_CONTEXT } from "../utils/toolbar";
6
+ import { resolveSlot, useComponentTheme, useRootProps } from "../utils/ui";
7
+ import Button from "./Button.vue";
8
+ import Icon from "./Icon.vue";
9
+ defineOptions({ inheritAttrs: false });
10
+ const props = defineProps({
11
+ items: { type: Array, required: true },
12
+ type: { type: String, required: false, default: "single" },
13
+ modelValue: { type: [String, Array], required: false },
14
+ defaultValue: { type: [String, Array], required: false },
15
+ disabled: { type: Boolean, required: false },
16
+ iconOnly: { type: Boolean, required: false },
17
+ size: { type: String, required: false },
18
+ color: { type: null, required: false },
19
+ ui: { type: Object, required: false }
20
+ });
21
+ const emit = defineEmits(["update:modelValue"]);
22
+ defineSlots();
23
+ const toolbar = inject(TOOLBAR_CONTEXT, void 0);
24
+ const disabled = computed(() => props.disabled || toolbar?.value.disabled);
25
+ const size = computed(() => props.size ?? toolbar?.value.size ?? "sm");
26
+ const color = computed(() => props.color ?? toolbar?.value.color ?? "primary");
27
+ const items = computed(() => props.items.map((item) => typeof item === "string" ? { value: item, label: item } : item));
28
+ const theme = useComponentTheme("toolbarToggleGroup", toolbarToggleGroupTheme);
29
+ const ui = computed(() => theme.value({ size: size.value, orientation: toolbar?.value.orientation }));
30
+ const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root);
31
+ </script>
32
+
33
+ <template>
34
+ <ToolbarToggleGroup :type="type" :model-value="modelValue" :default-value="defaultValue" :disabled="disabled" v-bind="rootProps" @update:model-value="emit('update:modelValue', $event)">
35
+ <ToolbarToggleItem v-for="item in items" :key="item.value" as-child :value="item.value" :disabled="disabled || item.disabled">
36
+ <Button :size="size" :color="color" variant="ghost" :disabled="disabled || item.disabled" :square="iconOnly" :aria-label="iconOnly ? item.label : void 0" :title="iconOnly ? item.label : void 0" :ui="{ base: resolveSlot(ui.item, props.ui?.item) }">
37
+ <slot name="item" :item="item">
38
+ <Icon v-if="item.icon" :name="item.icon" v-bind="resolveSlot(ui.icon, props.ui?.icon)" />
39
+ <span v-if="!iconOnly">{{ item.label }}</span>
40
+ </slot>
41
+ </Button>
42
+ </ToolbarToggleItem>
43
+ </ToolbarToggleGroup>
44
+ </template>
@@ -0,0 +1,37 @@
1
+ import type { ToolbarToggleGroupThemeSlots } from '../theme/toolbar-toggle-group.js';
2
+ import type { ColorRole } from '../utils/color-registry.js';
3
+ import type { UiProp } from '../utils/ui.js';
4
+ import type { ToggleGroupItemDef } from './ToggleGroup.vue.js';
5
+ type __VLS_Slots = ToolbarToggleGroupSlots;
6
+ export interface ToolbarToggleGroupProps {
7
+ items: (string | ToggleGroupItemDef)[];
8
+ type?: 'single' | 'multiple';
9
+ modelValue?: string | string[];
10
+ defaultValue?: string | string[];
11
+ disabled?: boolean;
12
+ iconOnly?: boolean;
13
+ size?: 'sm' | 'md' | 'lg';
14
+ color?: ColorRole;
15
+ ui?: UiProp<ToolbarToggleGroupThemeSlots>;
16
+ }
17
+ export interface ToolbarToggleGroupEmits {
18
+ 'update:modelValue': [value: string | string[]];
19
+ }
20
+ export interface ToolbarToggleGroupSlots {
21
+ item?: (props: {
22
+ item: ToggleGroupItemDef;
23
+ }) => any;
24
+ }
25
+ declare const __VLS_base: import("vue").DefineComponent<ToolbarToggleGroupProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
26
+ "update:modelValue": (value: string | string[]) => any;
27
+ }, string, import("vue").PublicProps, Readonly<ToolbarToggleGroupProps> & Readonly<{
28
+ "onUpdate:modelValue"?: ((value: string | string[]) => any) | undefined;
29
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
31
+ declare const _default: typeof __VLS_export;
32
+ export default _default;
33
+ type __VLS_WithSlots<T, S> = T & {
34
+ new (): {
35
+ $slots: S;
36
+ };
37
+ };
@@ -16,7 +16,7 @@ import {
16
16
  TagsInputRoot,
17
17
  useDirection
18
18
  } from "reka-ui";
19
- import { computed, getCurrentInstance, mergeProps, nextTick, onMounted, onUnmounted, ref, useId, watch } from "vue";
19
+ import { computed, getCurrentInstance, mergeProps, nextTick, onMounted, onUnmounted, ref, useAttrs, useId, watch } from "vue";
20
20
  import Button from "../components/Button.vue";
21
21
  import Chip from "../components/Chip.vue";
22
22
  import Icon from "../components/Icon.vue";
@@ -29,12 +29,14 @@ import { useMessages } from "../composables/use-messages";
29
29
  import { selectTheme } from "../theme/select";
30
30
  import { arrowContentProps, arrowElementProps } from "../utils/arrow";
31
31
  import { useFieldAdornments } from "../utils/field-adornments";
32
+ import { canClearField, isFieldReadonly } from "../utils/field-clear";
32
33
  import { isNativeInputA11yAttr, isNativeInputAttr, isNativeInputEvent } from "../utils/native-input";
33
34
  import { overlayPortalProps } from "../utils/overlay";
34
35
  import { resolveRegisteredColorRole } from "../utils/registered-colors";
35
36
  import { applyClassPrefix, resolveSlot, useComponentTheme, useFallthroughAttrs, useRootProps, useThemeBindings } from "../utils/ui";
36
37
  import { useComboboxSelect } from "./combobox-select";
37
38
  import ComboboxSelectBody from "./ComboboxSelectBody.vue";
39
+ import FieldClearButton from "./FieldClearButton.vue";
38
40
  defineOptions({ inheritAttrs: false });
39
41
  const props = defineProps({
40
42
  id: { type: String, required: false },
@@ -76,6 +78,7 @@ const emit = defineEmits(["update:open", "update:modelValue", "update:searchTerm
76
78
  const slots = defineSlots();
77
79
  const { leading, trailing, padding } = useFieldAdornments();
78
80
  const instance = getCurrentInstance();
81
+ const attrs = useAttrs();
79
82
  const initialValue = Array.isArray(props.defaultValue) ? [...props.defaultValue] : props.defaultValue;
80
83
  const isControlled = () => Object.hasOwn(instance.vnode.props ?? {}, "modelValue") || Object.hasOwn(instance.vnode.props ?? {}, "model-value");
81
84
  function selectionForMode(value, multiple) {
@@ -164,9 +167,6 @@ const {
164
167
  } = useComboboxSelect(new Proxy(props, {
165
168
  get: (target, key) => key === "modelValue" ? selection.value : Reflect.get(target, key)
166
169
  }), updateSelection, { creatable: props.creatable });
167
- function clear() {
168
- setValue(props.multiple ? [] : void 0);
169
- }
170
170
  const selectedChipValue = ref();
171
171
  const dir = useDirection();
172
172
  function onTriggerKeydown(event) {
@@ -237,6 +237,12 @@ const searchText = computed({
237
237
  emit("update:searchTerm", value);
238
238
  }
239
239
  });
240
+ const showClear = computed(() => canClearField(
241
+ props.clearable,
242
+ selectedValues.value.length > 0 || !!props.creatable && searchText.value.length > 0,
243
+ props.disabled,
244
+ isFieldReadonly(attrs.readonly)
245
+ ));
240
246
  const isSearchComposing = ref(false);
241
247
  function onSearchCompositionStart() {
242
248
  isSearchComposing.value = true;
@@ -415,8 +421,8 @@ const searchDescribedBy = computed(() => [
415
421
  props.creatable && props.multiple && props.displayMode === "comma" && selectedOptions.value.length ? selectedSummaryId : void 0
416
422
  ].filter(Boolean).join(" ") || void 0);
417
423
  const effectiveSize = computed(() => props.size ?? field?.size ?? "md");
418
- const clearSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
419
- const adornmentScope = computed(() => ({ disabled: !!props.disabled, size: effectiveSize.value, buttonSize: clearSize.value }));
424
+ const adornmentButtonSize = computed(() => ({ sm: "sm", md: "sm", lg: "md" })[effectiveSize.value]);
425
+ const adornmentScope = computed(() => ({ disabled: !!props.disabled, size: effectiveSize.value, buttonSize: adornmentButtonSize.value }));
420
426
  const icons = useIcons();
421
427
  const messages = useMessages();
422
428
  const theme = useComponentTheme("select", selectTheme);
@@ -586,6 +592,17 @@ const bodyProps = computed(() => ({
586
592
  itemProps: itemProps.value,
587
593
  itemIndicatorProps: itemIndicatorProps.value
588
594
  }));
595
+ async function clear() {
596
+ if (!showClear.value)
597
+ return;
598
+ searchText.value = "";
599
+ setValue(props.multiple ? [] : void 0);
600
+ await nextTick();
601
+ if (props.creatable)
602
+ activeEditableInput.value?.focus();
603
+ else
604
+ selectTrigger.value?.$el?.focus();
605
+ }
589
606
  </script>
590
607
 
591
608
  <template>
@@ -723,29 +740,18 @@ const bodyProps = computed(() => ({
723
740
  display-value re-syncs the visible text once modelValue changes.
724
741
  tabindex="-1" replicates the one bit of its behavior this used.
725
742
  -->
726
- <Button
727
- v-if="clearable && !disabled && selectedOptions.length"
728
- :size="clearSize"
729
- variant="text"
730
- color="neutral"
731
- tabindex="-1"
732
- :aria-label="messages.clear"
733
- v-bind="clearProps"
734
- @click.stop="clear"
735
- >
736
- <template #icon="{ class: iconClass }">
737
- <slot name="clear-icon">
738
- <Icon :name="icons.close" :class="iconClass" />
739
- </slot>
743
+ <FieldClearButton v-if="showClear" :size="effectiveSize" tabindex="-1" v-bind="clearProps" @click.stop="clear">
744
+ <template v-if="slots['clear-icon']" #default>
745
+ <slot name="clear-icon" />
740
746
  </template>
741
- </Button>
747
+ </FieldClearButton>
742
748
  <slot v-if="loading" name="loading-icon">
743
- <Icon :name="icons.loading" class="size-4 animate-spin" v-bind="iconProps" />
749
+ <Icon :name="icons.loading" class="animate-spin" v-bind="iconProps" />
744
750
  </slot>
745
751
  <span v-if="loading" class="sr-only">{{ messages.loading }}</span>
746
752
  <ComboboxTrigger v-if="dropdown" v-bind="dropdownProps" @click="onDropdownClick">
747
753
  <slot name="dropdown-icon">
748
- <Icon :name="icons.chevronDown" class="size-4" />
754
+ <Icon :name="icons.chevronDown" v-bind="iconProps" />
749
755
  </slot>
750
756
  </ComboboxTrigger>
751
757
  </div>
@@ -775,21 +781,19 @@ const bodyProps = computed(() => ({
775
781
  :aria-controls="modalId"
776
782
  @keydown="openMobileAutocomplete"
777
783
  >
778
- <Button v-if="clearable && !disabled && selectedOptions.length" :size="clearSize" variant="text" color="neutral" tabindex="-1" :aria-label="messages.clear" v-bind="clearProps" @click.stop="clear">
779
- <template #icon>
780
- <slot name="clear-icon">
781
- <Icon :name="icons.close" class="size-4" />
782
- </slot>
784
+ <FieldClearButton v-if="showClear" :size="effectiveSize" tabindex="-1" v-bind="clearProps" @click.stop="clear">
785
+ <template v-if="slots['clear-icon']" #default>
786
+ <slot name="clear-icon" />
783
787
  </template>
784
- </Button>
788
+ </FieldClearButton>
785
789
  <slot v-if="loading" name="loading-icon">
786
- <Icon :name="icons.loading" class="size-4 animate-spin" v-bind="iconProps" />
790
+ <Icon :name="icons.loading" class="animate-spin" v-bind="iconProps" />
787
791
  </slot>
788
792
  <span v-if="loading" class="sr-only">{{ messages.loading }}</span>
789
793
  <button v-if="dropdown" type="button" tabindex="-1" :disabled="disabled" :aria-label="messages.search" v-bind="dropdownProps" @click.stop="onDropdownClick();
790
794
  openMobileAutocomplete()">
791
795
  <slot name="dropdown-icon">
792
- <Icon :name="icons.chevronDown" class="size-4" />
796
+ <Icon :name="icons.chevronDown" v-bind="iconProps" />
793
797
  </slot>
794
798
  </button>
795
799
  </div>
@@ -874,32 +878,19 @@ const bodyProps = computed(() => ({
874
878
  already set here regardless, so nothing about keyboard
875
879
  reachability changes.
876
880
  -->
877
- <Button
878
- v-if="clearable && !disabled && selectedOptions.length"
879
- as="span"
880
- role="button"
881
- :size="clearSize"
882
- variant="text"
883
- color="neutral"
884
- tabindex="-1"
885
- :aria-label="messages.clear"
886
- v-bind="clearProps"
887
- @click.stop="clear"
888
- >
889
- <template #icon="{ class: iconClass }">
890
- <slot name="clear-icon">
891
- <Icon :name="icons.close" :class="iconClass" />
892
- </slot>
881
+ <FieldClearButton v-if="showClear" as="span" role="button" :size="effectiveSize" tabindex="-1" v-bind="clearProps" @click.stop="clear">
882
+ <template v-if="slots['clear-icon']" #default>
883
+ <slot name="clear-icon" />
893
884
  </template>
894
- </Button>
885
+ </FieldClearButton>
895
886
  <template v-if="loading">
896
887
  <slot name="loading-icon">
897
- <Icon :name="icons.loading" class="size-4 animate-spin" v-bind="iconProps" />
888
+ <Icon :name="icons.loading" class="animate-spin" v-bind="iconProps" />
898
889
  </slot>
899
890
  </template>
900
891
  <template v-else>
901
892
  <slot name="dropdown-icon">
902
- <Icon :name="icons.chevronDown" class="size-4" v-bind="iconProps" />
893
+ <Icon :name="icons.chevronDown" v-bind="iconProps" />
903
894
  </slot>
904
895
  </template>
905
896
  <span v-if="loading" class="sr-only">{{ messages.loading }}</span>
@@ -0,0 +1,21 @@
1
+ import type { ButtonThemeSlots } from '../theme/button.js';
2
+ import type { UiProp } from '../utils/ui.js';
3
+ type __VLS_Props = {
4
+ size?: 'sm' | 'md' | 'lg';
5
+ ui?: UiProp<ButtonThemeSlots>;
6
+ };
7
+ declare var __VLS_11: {
8
+ class: unknown;
9
+ };
10
+ type __VLS_Slots = {} & {
11
+ default?: (props: typeof __VLS_11) => any;
12
+ };
13
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
14
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_WithSlots<T, S> = T & {
18
+ new (): {
19
+ $slots: S;
20
+ };
21
+ };