@sewadah/selaras 0.3.1 → 0.4.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 (63) hide show
  1. package/README.md +10 -1
  2. package/agent/catalog.mjs +73 -0
  3. package/agent/mcp.mjs +15 -0
  4. package/agent/server.mjs +58 -0
  5. package/dist/agent/catalog.json +1 -0
  6. package/dist/module.json +1 -1
  7. package/dist/module.mjs +7 -5
  8. package/dist/runtime/components/AlertDialog.d.vue.ts +5 -3
  9. package/dist/runtime/components/AlertDialog.vue +17 -9
  10. package/dist/runtime/components/AlertDialog.vue.d.ts +5 -3
  11. package/dist/runtime/components/App.vue +2 -0
  12. package/dist/runtime/components/Autocomplete.d.vue.ts +2 -2
  13. package/dist/runtime/components/Autocomplete.vue +1 -1
  14. package/dist/runtime/components/Autocomplete.vue.d.ts +2 -2
  15. package/dist/runtime/components/Button.d.vue.ts +7 -5
  16. package/dist/runtime/components/Button.vue +14 -3
  17. package/dist/runtime/components/Button.vue.d.ts +7 -5
  18. package/dist/runtime/components/ColorModeSwitch.d.vue.ts +18 -0
  19. package/dist/runtime/components/ColorModeSwitch.vue +59 -0
  20. package/dist/runtime/components/ColorModeSwitch.vue.d.ts +18 -0
  21. package/dist/runtime/components/ConfirmRenderer.d.vue.ts +3 -0
  22. package/dist/runtime/components/ConfirmRenderer.vue +39 -0
  23. package/dist/runtime/components/ConfirmRenderer.vue.d.ts +3 -0
  24. package/dist/runtime/components/ContextMenu.vue +4 -2
  25. package/dist/runtime/components/Drawer.vue +3 -2
  26. package/dist/runtime/components/Dropdown.vue +4 -2
  27. package/dist/runtime/components/Modal.vue +3 -2
  28. package/dist/runtime/components/Popover.vue +4 -2
  29. package/dist/runtime/components/Select.d.vue.ts +8 -4
  30. package/dist/runtime/components/Select.vue +1 -1
  31. package/dist/runtime/components/Select.vue.d.ts +8 -4
  32. package/dist/runtime/components/Slideover.vue +3 -2
  33. package/dist/runtime/components/Tooltip.vue +4 -2
  34. package/dist/runtime/composables/use-confirm.d.ts +14 -0
  35. package/dist/runtime/composables/use-confirm.js +28 -0
  36. package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +41 -32
  37. package/dist/runtime/internal/ComboboxSelectBase.vue +154 -68
  38. package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +41 -32
  39. package/dist/runtime/internal/ComboboxSelectBody.d.vue.ts +9 -7
  40. package/dist/runtime/internal/ComboboxSelectBody.vue +6 -6
  41. package/dist/runtime/internal/ComboboxSelectBody.vue.d.ts +9 -7
  42. package/dist/runtime/internal/combobox-select.d.ts +19 -18
  43. package/dist/runtime/internal/combobox-select.js +36 -14
  44. package/dist/runtime/internal/programmatic-services.d.ts +11 -0
  45. package/dist/runtime/internal/programmatic-services.js +1 -0
  46. package/dist/runtime/theme/badge.d.ts +9 -0
  47. package/dist/runtime/theme/badge.js +2 -1
  48. package/dist/runtime/theme/button.d.ts +18 -0
  49. package/dist/runtime/theme/button.js +4 -1
  50. package/dist/runtime/theme/select.js +1 -4
  51. package/dist/runtime/theme/toast.js +1 -1
  52. package/dist/runtime/theme-config.d.ts +1 -1
  53. package/dist/runtime/types/index.d.ts +4 -1
  54. package/dist/runtime/utils/autocomplete-contracts.d.ts +4 -4
  55. package/dist/runtime/utils/file-icons.js +1 -0
  56. package/dist/runtime/utils/messages.d.ts +1 -0
  57. package/dist/runtime/utils/messages.js +1 -0
  58. package/dist/runtime/utils/select-contracts.d.ts +18 -10
  59. package/dist/runtime/utils/ui.d.ts +11 -0
  60. package/dist/runtime/utils/ui.js +54 -1
  61. package/package.json +19 -9
  62. package/skills/selaras/SKILL.md +40 -0
  63. package/skills/selaras/agents/openai.yaml +4 -0
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "selaras",
3
3
  "configKey": "selaras",
4
- "version": "0.3.1",
4
+ "version": "0.4.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.3",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -86,10 +86,11 @@ const module$1 = defineNuxtModule({
86
86
  path: resolver.resolve("./runtime/components"),
87
87
  prefix: options.prefix,
88
88
  pathPrefix: false,
89
- // SColumn/SColumnGroup are plain .ts files (never render real DOM), not
90
- // .vue SFCs - addComponentsDir only scans .vue by default.
91
- extensions: ["vue", "ts"],
92
- // ModalRenderer is App.vue's own internal render loop for useModal(),
89
+ // SColumn/SColumnGroup are plain render-function modules (never render
90
+ // real DOM). Source uses .ts; the published build emits .js.
91
+ extensions: ["vue", "ts", "js"],
92
+ // ModalRenderer/ConfirmRenderer are App.vue's internal render loops for
93
+ // useModal()/useConfirm(),
93
94
  // mirroring the same un-exported overlay-provider pattern other Nuxt
94
95
  // component libraries commonly use internally - not meant to be
95
96
  // placed by a consumer (App.vue already mounts one; a second copy
@@ -102,7 +103,7 @@ const module$1 = defineNuxtModule({
102
103
  // meant to be placed directly either. SlideoverRenderer/DrawerRenderer
103
104
  // are useSlideover()'s/useDrawer()'s own render loops, same reasoning
104
105
  // as ModalRenderer.
105
- ignore: ["**/ModalRenderer.vue", "**/NavigationMenuAccordionItem.vue", "**/NavigationMenuFlyoutList.vue", "**/NavigationMenuFlyoutTrigger.vue", "**/SlideoverRenderer.vue", "**/DrawerRenderer.vue"]
106
+ ignore: ["**/ModalRenderer.vue", "**/ConfirmRenderer.vue", "**/NavigationMenuAccordionItem.vue", "**/NavigationMenuFlyoutList.vue", "**/NavigationMenuFlyoutTrigger.vue", "**/SlideoverRenderer.vue", "**/DrawerRenderer.vue"]
106
107
  });
107
108
  const hasContentModule = nuxt.options.modules.some((m) => {
108
109
  const name = typeof m === "string" ? m : Array.isArray(m) && typeof m[0] === "string" ? m[0] : void 0;
@@ -120,6 +121,7 @@ const module$1 = defineNuxtModule({
120
121
  }
121
122
  addImports([
122
123
  { name: "useCommandPalette", from: resolver.resolve("./runtime/composables/use-command-palette") },
124
+ { name: "useConfirm", from: resolver.resolve("./runtime/composables/use-confirm") },
123
125
  { name: "useDrawer", from: resolver.resolve("./runtime/composables/use-drawer") },
124
126
  { name: "useIcons", from: resolver.resolve("./runtime/composables/use-icons") },
125
127
  { name: "useLocale", from: resolver.resolve("./runtime/composables/use-locale") },
@@ -7,6 +7,8 @@ export interface AlertDialogProps {
7
7
  defaultOpen?: boolean;
8
8
  title?: string;
9
9
  description?: string;
10
+ /** Optional icon shown beside the dialog heading. */
11
+ icon?: string;
10
12
  /** Label for the default Cancel button - only rendered when no `footer` slot is given. @default 'Cancel' */
11
13
  cancelLabel?: string;
12
14
  /** Label for the default action button - only rendered when no `footer` slot is given. @default 'Continue' */
@@ -33,15 +35,15 @@ export interface AlertDialogEmits {
33
35
  /** Fires once the close transition has actually finished (or immediately, if `transition` is off) - the signal a programmatic caller needs before it's safe to unmount this instance without cutting its exit animation short. */
34
36
  'afterLeave': [];
35
37
  }
36
- declare var __VLS_16: {}, __VLS_39: {}, __VLS_53: {}, __VLS_55: {};
38
+ declare var __VLS_16: {}, __VLS_39: {}, __VLS_58: {}, __VLS_60: {};
37
39
  type __VLS_Slots = {} & {
38
40
  default?: (props: typeof __VLS_16) => any;
39
41
  } & {
40
42
  header?: (props: typeof __VLS_39) => any;
41
43
  } & {
42
- body?: (props: typeof __VLS_53) => any;
44
+ body?: (props: typeof __VLS_58) => any;
43
45
  } & {
44
- footer?: (props: typeof __VLS_55) => any;
46
+ footer?: (props: typeof __VLS_60) => any;
45
47
  };
46
48
  declare const __VLS_base: import("vue").DefineComponent<AlertDialogProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
47
49
  cancel: () => any;
@@ -3,13 +3,16 @@ import { AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDe
3
3
  import { computed, getCurrentInstance, ref, useSlots, watch, watchEffect } from "vue";
4
4
  import { useMessages } from "../composables/use-messages";
5
5
  import { alertDialogTheme } from "../theme/alert-dialog";
6
- import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
6
+ import { resolveSlot, useComponentTheme, useRootProps, useThemeBindings } from "../utils/ui";
7
7
  import Button from "./Button.vue";
8
+ import Icon from "./Icon.vue";
9
+ defineOptions({ inheritAttrs: false });
8
10
  const props = defineProps({
9
11
  open: { type: Boolean, required: false, default: void 0 },
10
12
  defaultOpen: { type: Boolean, required: false },
11
13
  title: { type: String, required: false },
12
14
  description: { type: String, required: false },
15
+ icon: { type: String, required: false },
13
16
  cancelLabel: { type: String, required: false },
14
17
  actionLabel: { type: String, required: false },
15
18
  actionColor: { type: null, required: false },
@@ -65,8 +68,8 @@ const messages = useMessages();
65
68
  const theme = useComponentTheme("alertDialog", alertDialogTheme);
66
69
  const themeBindings = useThemeBindings();
67
70
  const ui = computed(() => theme.value({ transition: props.transition }));
71
+ const contentProps = useRootProps(() => ui.value.content, () => props.ui?.content);
68
72
  const overlayProps = computed(() => resolveSlot(ui.value.overlay, props.ui?.overlay));
69
- const contentProps = computed(() => resolveSlot(ui.value.content, props.ui?.content));
70
73
  const headerProps = computed(() => resolveSlot(ui.value.header, props.ui?.header));
71
74
  const titleProps = computed(() => resolveSlot(ui.value.title, props.ui?.title));
72
75
  const descriptionProps = computed(() => resolveSlot(ui.value.description, props.ui?.description));
@@ -96,14 +99,19 @@ const footerProps = computed(() => resolveSlot(ui.value.footer, props.ui?.footer
96
99
  @pointer-down-outside="onPointerDownOutside"
97
100
  @animationend="onContentAnimationEnd"
98
101
  >
99
- <div v-if="title || description || $slots.header" v-bind="headerProps">
102
+ <div v-if="title || description || icon || $slots.header" v-bind="headerProps">
100
103
  <slot name="header">
101
- <AlertDialogTitle v-if="title" v-bind="titleProps">
102
- {{ title }}
103
- </AlertDialogTitle>
104
- <AlertDialogDescription v-if="description" v-bind="descriptionProps">
105
- {{ description }}
106
- </AlertDialogDescription>
104
+ <div class="flex items-start gap-3">
105
+ <Icon v-if="icon" :name="icon" class="mt-0.5 size-5 shrink-0" aria-hidden="true" />
106
+ <div class="min-w-0">
107
+ <AlertDialogTitle v-if="title" v-bind="titleProps">
108
+ {{ title }}
109
+ </AlertDialogTitle>
110
+ <AlertDialogDescription v-if="description" v-bind="descriptionProps">
111
+ {{ description }}
112
+ </AlertDialogDescription>
113
+ </div>
114
+ </div>
107
115
  </slot>
108
116
  </div>
109
117
  <div v-if="$slots.body" v-bind="bodyProps">
@@ -7,6 +7,8 @@ export interface AlertDialogProps {
7
7
  defaultOpen?: boolean;
8
8
  title?: string;
9
9
  description?: string;
10
+ /** Optional icon shown beside the dialog heading. */
11
+ icon?: string;
10
12
  /** Label for the default Cancel button - only rendered when no `footer` slot is given. @default 'Cancel' */
11
13
  cancelLabel?: string;
12
14
  /** Label for the default action button - only rendered when no `footer` slot is given. @default 'Continue' */
@@ -33,15 +35,15 @@ export interface AlertDialogEmits {
33
35
  /** Fires once the close transition has actually finished (or immediately, if `transition` is off) - the signal a programmatic caller needs before it's safe to unmount this instance without cutting its exit animation short. */
34
36
  'afterLeave': [];
35
37
  }
36
- declare var __VLS_16: {}, __VLS_39: {}, __VLS_53: {}, __VLS_55: {};
38
+ declare var __VLS_16: {}, __VLS_39: {}, __VLS_58: {}, __VLS_60: {};
37
39
  type __VLS_Slots = {} & {
38
40
  default?: (props: typeof __VLS_16) => any;
39
41
  } & {
40
42
  header?: (props: typeof __VLS_39) => any;
41
43
  } & {
42
- body?: (props: typeof __VLS_53) => any;
44
+ body?: (props: typeof __VLS_58) => any;
43
45
  } & {
44
- footer?: (props: typeof __VLS_55) => any;
46
+ footer?: (props: typeof __VLS_60) => any;
45
47
  };
46
48
  declare const __VLS_base: import("vue").DefineComponent<AlertDialogProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
47
49
  cancel: () => any;
@@ -4,6 +4,7 @@ import { computed } from "vue";
4
4
  import { useAppConfig, useHead } from "#imports";
5
5
  import { useLocale } from "../composables/use-locale";
6
6
  import { generateRuntimeTokenOverrideCss } from "../utils/color-registry";
7
+ import ConfirmRenderer from "./ConfirmRenderer.vue";
7
8
  import DrawerRenderer from "./DrawerRenderer.vue";
8
9
  import ModalRenderer from "./ModalRenderer.vue";
9
10
  import SlideoverRenderer from "./SlideoverRenderer.vue";
@@ -29,5 +30,6 @@ useHead({
29
30
  <ModalRenderer />
30
31
  <SlideoverRenderer />
31
32
  <DrawerRenderer />
33
+ <ConfirmRenderer />
32
34
  </ConfigProvider>
33
35
  </template>
@@ -1,7 +1,7 @@
1
1
  import type { AutocompleteProps, AutocompleteSlots, AutocompleteValue } from '../utils/autocomplete-contracts.js';
2
- import type { SelectModel } from '../utils/select-contracts.js';
2
+ import type { SelectEntry, SelectModel } from '../utils/select-contracts.js';
3
3
  export type { AutocompleteEmits, AutocompleteProps, AutocompleteSlots } from '../utils/autocomplete-contracts.js';
4
- declare const __VLS_export: <Entry extends object, Key extends string = "value", Multiple extends boolean = false, Forced extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
4
+ declare const __VLS_export: <Entry extends SelectEntry, Key extends string = "value", Multiple extends boolean = false, Forced extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
5
5
  props: import("vue").PublicProps & __VLS_PrettifyLocal<AutocompleteProps<Entry, Key, Multiple, Forced> & {
6
6
  "onUpdate:modelValue"?: ((value: SelectModel<AutocompleteValue<Entry, Key, Forced>, Multiple>) => any) | undefined;
7
7
  "onUpdate:open"?: ((value: boolean) => any) | undefined;
@@ -11,7 +11,7 @@ const props = defineProps({
11
11
  name: { type: String, required: false },
12
12
  form: { type: String, required: false },
13
13
  items: { type: Array, required: true },
14
- valueKey: { type: String, required: false },
14
+ valueKey: { type: void 0, required: false },
15
15
  labelKey: { type: String, required: false },
16
16
  open: { type: Boolean, required: false },
17
17
  defaultOpen: { type: Boolean, required: false },
@@ -1,7 +1,7 @@
1
1
  import type { AutocompleteProps, AutocompleteSlots, AutocompleteValue } from '../utils/autocomplete-contracts.js';
2
- import type { SelectModel } from '../utils/select-contracts.js';
2
+ import type { SelectEntry, SelectModel } from '../utils/select-contracts.js';
3
3
  export type { AutocompleteEmits, AutocompleteProps, AutocompleteSlots } from '../utils/autocomplete-contracts.js';
4
- declare const __VLS_export: <Entry extends object, Key extends string = "value", Multiple extends boolean = false, Forced extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
4
+ declare const __VLS_export: <Entry extends SelectEntry, Key extends string = "value", Multiple extends boolean = false, Forced extends boolean = false>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
5
5
  props: import("vue").PublicProps & __VLS_PrettifyLocal<AutocompleteProps<Entry, Key, Multiple, Forced> & {
6
6
  "onUpdate:modelValue"?: ((value: SelectModel<AutocompleteValue<Entry, Key, Forced>, Multiple>) => any) | undefined;
7
7
  "onUpdate:open"?: ((value: boolean) => any) | undefined;
@@ -8,6 +8,8 @@ type ButtonVariants = VariantProps<typeof buttonTheme>;
8
8
  export interface ButtonProps {
9
9
  /** A tag name ('a', 'span', ...) or a component reference (e.g. NuxtLink, via resolveComponent) - Primitive renders whichever is given. */
10
10
  as?: string | Component;
11
+ /** Nuxt route or URL. Renders NuxtLink unless an explicit `as` overrides it. */
12
+ to?: string;
11
13
  /** Native button type when `as="button"`. Defaults to `button` so actions inside forms do not submit accidentally. */
12
14
  type?: 'button' | 'submit' | 'reset';
13
15
  color?: ColorRole;
@@ -25,17 +27,17 @@ export interface ButtonProps {
25
27
  square?: boolean;
26
28
  ui?: UiProp<ButtonThemeSlots>;
27
29
  }
28
- declare var __VLS_13: {
30
+ declare var __VLS_15: {
29
31
  class: unknown;
30
- }, __VLS_20: {}, __VLS_22: {
32
+ }, __VLS_22: {}, __VLS_24: {
31
33
  class: unknown;
32
34
  };
33
35
  type __VLS_Slots = {} & {
34
- icon?: (props: typeof __VLS_13) => any;
36
+ icon?: (props: typeof __VLS_15) => any;
35
37
  } & {
36
- default?: (props: typeof __VLS_20) => any;
38
+ default?: (props: typeof __VLS_22) => any;
37
39
  } & {
38
- 'trailing-icon'?: (props: typeof __VLS_22) => any;
40
+ 'trailing-icon'?: (props: typeof __VLS_24) => any;
39
41
  };
40
42
  declare const __VLS_base: import("vue").DefineComponent<ButtonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ButtonProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
41
43
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { Primitive } from "reka-ui";
3
- import { computed, useSlots } from "vue";
3
+ import { computed, getCurrentInstance, useSlots } from "vue";
4
+ import { NuxtLink } from "#components";
4
5
  import { useIcons } from "../composables/use-icons";
5
6
  import { useMessages } from "../composables/use-messages";
6
7
  import { useRippleEnabled } from "../composables/use-ripple";
@@ -12,6 +13,7 @@ import Icon from "./Icon.vue";
12
13
  defineOptions({ inheritAttrs: false });
13
14
  const props = defineProps({
14
15
  as: { type: null, required: false, default: "button" },
16
+ to: { type: String, required: false },
15
17
  type: { type: String, required: false, default: "button" },
16
18
  color: { type: null, required: false },
17
19
  variant: { type: null, required: false },
@@ -26,11 +28,20 @@ const props = defineProps({
26
28
  ui: { type: Object, required: false }
27
29
  });
28
30
  const slots = useSlots();
31
+ const hasExplicitAs = Object.hasOwn(getCurrentInstance()?.vnode.props ?? {}, "as");
32
+ const resolvedAs = computed(() => hasExplicitAs ? props.as : props.to ? NuxtLink : props.as);
33
+ const isNativeButton = computed(() => resolvedAs.value === "button");
34
+ function onClick(event) {
35
+ if (props.disabled && !isNativeButton.value) {
36
+ event.preventDefault();
37
+ event.stopPropagation();
38
+ }
39
+ }
29
40
  const iconOnly = computed(() => !slots.default);
30
41
  const icons = useIcons();
31
42
  const messages = useMessages();
32
43
  const rippleEnabledSetting = useRippleEnabled();
33
- const rippleEnabled = computed(() => rippleEnabledSetting.value && props.variant !== "text");
44
+ const rippleEnabled = computed(() => rippleEnabledSetting.value && props.variant !== "text" && props.variant !== "link");
34
45
  const theme = useComponentTheme("button", buttonTheme);
35
46
  const themeProps = useThemeProps("button");
36
47
  const effectiveColor = computed(() => resolveRegisteredColorRole(props.color ?? themeProps.value.color ?? "primary", "primary"));
@@ -46,7 +57,7 @@ const rootProps = useRootProps(() => ui.value.base, () => props.ui?.base);
46
57
  </script>
47
58
 
48
59
  <template>
49
- <Primitive v-ripple="rippleEnabled" :as="as" :type="as === 'button' ? type : void 0" :disabled="disabled" :aria-busy="loading || void 0" :data-selaras-color="effectiveColor" v-bind="rootProps">
60
+ <Primitive v-ripple="rippleEnabled" :as="resolvedAs" :to="resolvedAs === NuxtLink || typeof resolvedAs !== 'string' ? to : void 0" :type="isNativeButton ? type : void 0" :disabled="isNativeButton ? disabled : void 0" :aria-disabled="!isNativeButton && disabled ? 'true' : void 0" :tabindex="!isNativeButton && disabled ? -1 : void 0" :aria-busy="loading || void 0" :data-selaras-color="effectiveColor" v-bind="rootProps" @click="onClick">
50
61
  <Icon v-if="loading" :name="icons.loading" :class="applyClassPrefix('animate-spin')" v-bind="resolveSlot(ui.leadingIcon, props.ui?.leadingIcon)" />
51
62
  <!--
52
63
  A named slot (not just the `icon` prop) so a consumer building a
@@ -8,6 +8,8 @@ type ButtonVariants = VariantProps<typeof buttonTheme>;
8
8
  export interface ButtonProps {
9
9
  /** A tag name ('a', 'span', ...) or a component reference (e.g. NuxtLink, via resolveComponent) - Primitive renders whichever is given. */
10
10
  as?: string | Component;
11
+ /** Nuxt route or URL. Renders NuxtLink unless an explicit `as` overrides it. */
12
+ to?: string;
11
13
  /** Native button type when `as="button"`. Defaults to `button` so actions inside forms do not submit accidentally. */
12
14
  type?: 'button' | 'submit' | 'reset';
13
15
  color?: ColorRole;
@@ -25,17 +27,17 @@ export interface ButtonProps {
25
27
  square?: boolean;
26
28
  ui?: UiProp<ButtonThemeSlots>;
27
29
  }
28
- declare var __VLS_13: {
30
+ declare var __VLS_15: {
29
31
  class: unknown;
30
- }, __VLS_20: {}, __VLS_22: {
32
+ }, __VLS_22: {}, __VLS_24: {
31
33
  class: unknown;
32
34
  };
33
35
  type __VLS_Slots = {} & {
34
- icon?: (props: typeof __VLS_13) => any;
36
+ icon?: (props: typeof __VLS_15) => any;
35
37
  } & {
36
- default?: (props: typeof __VLS_20) => any;
38
+ default?: (props: typeof __VLS_22) => any;
37
39
  } & {
38
- 'trailing-icon'?: (props: typeof __VLS_22) => any;
40
+ 'trailing-icon'?: (props: typeof __VLS_24) => any;
39
41
  };
40
42
  declare const __VLS_base: import("vue").DefineComponent<ButtonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ButtonProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
41
43
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -0,0 +1,18 @@
1
+ import type { SwitchProps } from './Switch.vue.js';
2
+ export interface ColorModeSwitchProps extends Pick<SwitchProps, 'id' | 'label' | 'description' | 'size' | 'color' | 'disabled' | 'checkedIcon' | 'uncheckedIcon' | 'ui'> {
3
+ }
4
+ declare var __VLS_11: {}, __VLS_14: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_11) => any;
7
+ } & {
8
+ description?: (props: typeof __VLS_14) => any;
9
+ };
10
+ declare const __VLS_base: import("vue").DefineComponent<ColorModeSwitchProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ColorModeSwitchProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
14
+ type __VLS_WithSlots<T, S> = T & {
15
+ new (): {
16
+ $slots: S;
17
+ };
18
+ };
@@ -0,0 +1,59 @@
1
+ <script setup>
2
+ import { computed, useAttrs, useSlots } from "vue";
3
+ import { useColorMode } from "#imports";
4
+ import { useIcons } from "../composables/use-icons";
5
+ import { useMessages } from "../composables/use-messages";
6
+ import Switch from "./Switch.vue";
7
+ defineOptions({ inheritAttrs: false });
8
+ const props = defineProps({
9
+ id: { type: String, required: false },
10
+ label: { type: String, required: false },
11
+ description: { type: String, required: false },
12
+ size: { type: null, required: false },
13
+ color: { type: null, required: false },
14
+ disabled: { type: Boolean, required: false },
15
+ checkedIcon: { type: String, required: false },
16
+ uncheckedIcon: { type: String, required: false },
17
+ ui: { type: Object, required: false }
18
+ });
19
+ const attrs = useAttrs();
20
+ const slots = useSlots();
21
+ const colorMode = useColorMode();
22
+ const icons = useIcons();
23
+ const messages = useMessages();
24
+ const isDark = computed(() => colorMode.value === "dark");
25
+ const switchUi = computed(() => {
26
+ const track = typeof props.ui?.track === "string" ? { class: props.ui.track } : props.ui?.track;
27
+ return {
28
+ ...props.ui,
29
+ track: {
30
+ "aria-label": attrs["aria-label"] ?? (props.label || slots.default ? void 0 : messages.value.colorModeToggle),
31
+ "aria-labelledby": attrs["aria-labelledby"],
32
+ "aria-describedby": attrs["aria-describedby"],
33
+ ...track
34
+ }
35
+ };
36
+ });
37
+ function updateMode(dark) {
38
+ colorMode.preference = dark ? "dark" : "light";
39
+ }
40
+ </script>
41
+
42
+ <template>
43
+ <Switch
44
+ v-bind="{ ...attrs, ...props }"
45
+ :model-value="isDark"
46
+ :disabled="disabled || colorMode.forced"
47
+ :checked-icon="checkedIcon ?? icons.darkMode"
48
+ :unchecked-icon="uncheckedIcon ?? icons.lightMode"
49
+ :ui="switchUi"
50
+ @update:model-value="updateMode"
51
+ >
52
+ <template v-if="$slots.default" #default>
53
+ <slot />
54
+ </template>
55
+ <template v-if="$slots.description" #description>
56
+ <slot name="description" />
57
+ </template>
58
+ </Switch>
59
+ </template>
@@ -0,0 +1,18 @@
1
+ import type { SwitchProps } from './Switch.vue.js';
2
+ export interface ColorModeSwitchProps extends Pick<SwitchProps, 'id' | 'label' | 'description' | 'size' | 'color' | 'disabled' | 'checkedIcon' | 'uncheckedIcon' | 'ui'> {
3
+ }
4
+ declare var __VLS_11: {}, __VLS_14: {};
5
+ type __VLS_Slots = {} & {
6
+ default?: (props: typeof __VLS_11) => any;
7
+ } & {
8
+ description?: (props: typeof __VLS_14) => any;
9
+ };
10
+ declare const __VLS_base: import("vue").DefineComponent<ColorModeSwitchProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ColorModeSwitchProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
14
+ type __VLS_WithSlots<T, S> = T & {
15
+ new (): {
16
+ $slots: S;
17
+ };
18
+ };
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,39 @@
1
+ <script setup>
2
+ import { onUnmounted } from "vue";
3
+ import { useConfirmService } from "../internal/programmatic-services";
4
+ import ProgrammaticTheme from "../internal/ProgrammaticTheme.vue";
5
+ import AlertDialog from "./AlertDialog.vue";
6
+ const { instances, close, remove, dispose } = useConfirmService();
7
+ onUnmounted(dispose);
8
+ function onUpdateOpen(id, open) {
9
+ if (open)
10
+ return;
11
+ queueMicrotask(() => {
12
+ const instance = instances.value.find((item) => item.id === id);
13
+ if (instance && !instance._settled)
14
+ close(id, false);
15
+ });
16
+ }
17
+ </script>
18
+
19
+ <template>
20
+ <ProgrammaticTheme
21
+ v-for="instance in instances"
22
+ :key="instance.id"
23
+ :snapshot="instance._theme"
24
+ >
25
+ <AlertDialog
26
+ :open="instance.isOpen"
27
+ :title="instance.title"
28
+ :description="instance.description"
29
+ :action-label="instance.confirmLabel"
30
+ :cancel-label="instance.cancelLabel"
31
+ :action-color="instance.confirmColor"
32
+ :icon="instance.icon"
33
+ @update:open="(open) => onUpdateOpen(instance.id, open)"
34
+ @cancel="close(instance.id, false)"
35
+ @confirm="close(instance.id, true)"
36
+ @after-leave="remove(instance.id)"
37
+ />
38
+ </ProgrammaticTheme>
39
+ </template>
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -5,8 +5,9 @@ import { vHotkey } from "../directives/hotkey";
5
5
  import ShortcutHint from "../internal/ShortcutHint.vue";
6
6
  import { contextMenuTheme } from "../theme/context-menu";
7
7
  import { overlayPortalProps } from "../utils/overlay";
8
- import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
8
+ import { resolveSlot, useComponentTheme, useFallthroughProps, useThemeBindings } from "../utils/ui";
9
9
  import Icon from "./Icon.vue";
10
+ defineOptions({ inheritAttrs: false });
10
11
  const props = defineProps({
11
12
  items: { type: Array, required: true },
12
13
  positioning: { type: Object, required: false },
@@ -18,6 +19,7 @@ const theme = useComponentTheme("contextMenu", contextMenuTheme);
18
19
  const open = ref(false);
19
20
  const themeBindings = useThemeBindings();
20
21
  const ui = computed(() => theme.value());
22
+ const triggerProps = useFallthroughProps();
21
23
  const contentProps = computed(() => ({ ...resolveSlot(ui.value.content, props.ui?.content), ...props.positioning }));
22
24
  const portalProps = computed(() => overlayPortalProps(props.portal));
23
25
  function itemPropsFor(item) {
@@ -34,7 +36,7 @@ function hotkeyFor(item) {
34
36
 
35
37
  <template>
36
38
  <ContextMenuRoot :open="open" @update:open="open = $event">
37
- <ContextMenuTrigger as-child>
39
+ <ContextMenuTrigger as-child v-bind="triggerProps">
38
40
  <slot />
39
41
  </ContextMenuTrigger>
40
42
  <ContextMenuPortal v-bind="portalProps">
@@ -4,9 +4,10 @@ import { computed, getCurrentInstance, ref, useSlots, watch, watchEffect } from
4
4
  import { useIcons } from "../composables/use-icons";
5
5
  import { useMessages } from "../composables/use-messages";
6
6
  import { drawerTheme } from "../theme/drawer";
7
- import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
7
+ import { resolveSlot, useComponentTheme, useRootProps, useThemeBindings } from "../utils/ui";
8
8
  import Button from "./Button.vue";
9
9
  import Icon from "./Icon.vue";
10
+ defineOptions({ inheritAttrs: false });
10
11
  const props = defineProps({
11
12
  open: { type: Boolean, required: false, default: void 0 },
12
13
  defaultOpen: { type: Boolean, required: false },
@@ -76,8 +77,8 @@ const messages = useMessages();
76
77
  const theme = useComponentTheme("drawer", drawerTheme);
77
78
  const themeBindings = useThemeBindings();
78
79
  const ui = computed(() => theme.value({ side: props.side, transition: props.transition }));
80
+ const contentProps = useRootProps(() => ui.value.content, () => props.ui?.content);
79
81
  const overlayProps = computed(() => resolveSlot(ui.value.overlay, props.ui?.overlay));
80
- const contentProps = computed(() => resolveSlot(ui.value.content, props.ui?.content));
81
82
  const handleProps = computed(() => resolveSlot(ui.value.handle, props.ui?.handle));
82
83
  const headerProps = computed(() => resolveSlot(ui.value.header, props.ui?.header));
83
84
  const titleProps = computed(() => resolveSlot(ui.value.title, props.ui?.title));
@@ -9,9 +9,10 @@ import ShortcutHint from "../internal/ShortcutHint.vue";
9
9
  import { dropdownTheme } from "../theme/dropdown";
10
10
  import { arrowContentProps, arrowElementProps } from "../utils/arrow";
11
11
  import { overlayPortalProps } from "../utils/overlay";
12
- import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
12
+ import { resolveSlot, useComponentTheme, useFallthroughProps, useThemeBindings } from "../utils/ui";
13
13
  import Icon from "./Icon.vue";
14
14
  import Modal from "./Modal.vue";
15
+ defineOptions({ inheritAttrs: false });
15
16
  const props = defineProps({
16
17
  items: { type: Array, required: true },
17
18
  open: { type: Boolean, required: false, default: void 0 },
@@ -41,6 +42,7 @@ const isMobile = useIsMobile();
41
42
  const modalId = `selaras-dropdown-modal-${useId()}`;
42
43
  const triggerElement = ref();
43
44
  const ui = computed(() => theme.value());
45
+ const triggerProps = useFallthroughProps();
44
46
  const contentProps = computed(() => ({ ...resolveSlot(ui.value.content, props.ui?.content), ...arrowContentProps(props.arrow), ...props.positioning }));
45
47
  const portalProps = computed(() => overlayPortalProps(props.portal));
46
48
  const arrowProps = computed(() => ({ ...resolveSlot(ui.value.arrow, props.ui?.arrow), ...arrowElementProps(props.arrow) }));
@@ -106,7 +108,7 @@ function onModalAfterLeave() {
106
108
 
107
109
  <template>
108
110
  <DropdownMenuRoot :open="desktopOpen" @update:open="onUpdateMenuOpen">
109
- <DropdownMenuTrigger ref="triggerElement" as-child>
111
+ <DropdownMenuTrigger ref="triggerElement" as-child v-bind="triggerProps">
110
112
  <slot />
111
113
  </DropdownMenuTrigger>
112
114
  <DropdownMenuPortal v-if="!mobilePresentation" v-bind="portalProps">
@@ -4,9 +4,10 @@ import { computed, getCurrentInstance, ref, useSlots, watch, watchEffect } from
4
4
  import { useIcons } from "../composables/use-icons";
5
5
  import { useMessages } from "../composables/use-messages";
6
6
  import { modalTheme } from "../theme/modal";
7
- import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
7
+ import { resolveSlot, useComponentTheme, useRootProps, useThemeBindings } from "../utils/ui";
8
8
  import Button from "./Button.vue";
9
9
  import Icon from "./Icon.vue";
10
+ defineOptions({ inheritAttrs: false });
10
11
  const props = defineProps({
11
12
  open: { type: Boolean, required: false, default: void 0 },
12
13
  defaultOpen: { type: Boolean, required: false },
@@ -84,8 +85,8 @@ const messages = useMessages();
84
85
  const theme = useComponentTheme("modal", modalTheme);
85
86
  const themeBindings = useThemeBindings();
86
87
  const ui = computed(() => theme.value({ fullscreen: internalFullscreen.value, transition: props.transition }));
88
+ const contentProps = useRootProps(() => ui.value.content, () => props.ui?.content);
87
89
  const overlayProps = computed(() => resolveSlot(ui.value.overlay, props.ui?.overlay));
88
- const contentProps = computed(() => resolveSlot(ui.value.content, props.ui?.content));
89
90
  const headerProps = computed(() => resolveSlot(ui.value.header, props.ui?.header));
90
91
  const headerActionsProps = computed(() => resolveSlot(ui.value.headerActions, props.ui?.headerActions));
91
92
  const titleProps = computed(() => resolveSlot(ui.value.title, props.ui?.title));
@@ -4,7 +4,8 @@ import { computed, getCurrentInstance, ref, watch } from "vue";
4
4
  import { popoverTheme } from "../theme/popover";
5
5
  import { arrowContentProps, arrowElementProps } from "../utils/arrow";
6
6
  import { overlayPortalProps } from "../utils/overlay";
7
- import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
7
+ import { resolveSlot, useComponentTheme, useFallthroughProps, useThemeBindings } from "../utils/ui";
8
+ defineOptions({ inheritAttrs: false });
8
9
  const props = defineProps({
9
10
  open: { type: Boolean, required: false, default: void 0 },
10
11
  defaultOpen: { type: Boolean, required: false },
@@ -45,6 +46,7 @@ function onOpenAutoFocus(event) {
45
46
  const theme = useComponentTheme("popover", popoverTheme);
46
47
  const themeBindings = useThemeBindings();
47
48
  const ui = computed(() => theme.value());
49
+ const triggerProps = useFallthroughProps();
48
50
  const contentProps = computed(() => ({ ...resolveSlot(ui.value.content, props.ui?.content), ...arrowContentProps(props.arrow), ...props.positioning }));
49
51
  const portalProps = computed(() => overlayPortalProps(props.portal));
50
52
  const arrowProps = computed(() => ({ ...resolveSlot(ui.value.arrow, props.ui?.arrow), ...arrowElementProps(props.arrow) }));
@@ -63,7 +65,7 @@ function onUpdateOpen(value) {
63
65
 
64
66
  <template>
65
67
  <PopoverRoot :open="internalOpen" :modal="modal" @update:open="onUpdateOpen">
66
- <PopoverTrigger v-if="$slots.default" as-child>
68
+ <PopoverTrigger v-if="$slots.default" as-child v-bind="triggerProps">
67
69
  <slot />
68
70
  </PopoverTrigger>
69
71
  <PopoverPortal v-bind="portalProps">