@sewadah/selaras 0.3.0 → 0.3.2

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 (172) hide show
  1. package/README.md +4 -1
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +21 -6
  4. package/dist/runtime/components/AlertDialog.d.vue.ts +5 -3
  5. package/dist/runtime/components/AlertDialog.vue +17 -9
  6. package/dist/runtime/components/AlertDialog.vue.d.ts +5 -3
  7. package/dist/runtime/components/App.vue +2 -0
  8. package/dist/runtime/components/Autocomplete.d.vue.ts +2 -2
  9. package/dist/runtime/components/Autocomplete.vue +4 -2
  10. package/dist/runtime/components/Autocomplete.vue.d.ts +2 -2
  11. package/dist/runtime/components/Button.d.vue.ts +7 -5
  12. package/dist/runtime/components/Button.vue +14 -3
  13. package/dist/runtime/components/Button.vue.d.ts +7 -5
  14. package/dist/runtime/components/Calendar.d.vue.ts +69 -0
  15. package/dist/runtime/components/Calendar.vue +163 -0
  16. package/dist/runtime/components/Calendar.vue.d.ts +69 -0
  17. package/dist/runtime/components/Callout.vue +12 -1
  18. package/dist/runtime/components/CodeGroup.vue +13 -3
  19. package/dist/runtime/components/CodeTree.d.vue.ts +2 -0
  20. package/dist/runtime/components/CodeTree.vue +52 -1
  21. package/dist/runtime/components/CodeTree.vue.d.ts +2 -0
  22. package/dist/runtime/components/ColorModeSwitch.d.vue.ts +18 -0
  23. package/dist/runtime/components/ColorModeSwitch.vue +59 -0
  24. package/dist/runtime/components/ColorModeSwitch.vue.d.ts +18 -0
  25. package/dist/runtime/components/ColorPicker.d.vue.ts +8 -0
  26. package/dist/runtime/components/ColorPicker.vue +66 -45
  27. package/dist/runtime/components/ColorPicker.vue.d.ts +8 -0
  28. package/dist/runtime/components/Column.js +1 -1
  29. package/dist/runtime/components/CommandPalette.d.vue.ts +3 -1
  30. package/dist/runtime/components/CommandPalette.vue +5 -0
  31. package/dist/runtime/components/CommandPalette.vue.d.ts +3 -1
  32. package/dist/runtime/components/ConfirmRenderer.d.vue.ts +3 -0
  33. package/dist/runtime/components/ConfirmRenderer.vue +39 -0
  34. package/dist/runtime/components/ConfirmRenderer.vue.d.ts +3 -0
  35. package/dist/runtime/components/ContentNavigation.d.vue.ts +8 -1
  36. package/dist/runtime/components/ContentNavigation.vue +9 -2
  37. package/dist/runtime/components/ContentNavigation.vue.d.ts +8 -1
  38. package/dist/runtime/components/ContextMenu.d.vue.ts +8 -1
  39. package/dist/runtime/components/ContextMenu.vue +20 -6
  40. package/dist/runtime/components/ContextMenu.vue.d.ts +8 -1
  41. package/dist/runtime/components/DatePicker.d.vue.ts +10 -3
  42. package/dist/runtime/components/DatePicker.vue +24 -16
  43. package/dist/runtime/components/DatePicker.vue.d.ts +10 -3
  44. package/dist/runtime/components/Drawer.vue +3 -2
  45. package/dist/runtime/components/Dropdown.d.vue.ts +33 -6
  46. package/dist/runtime/components/Dropdown.vue +146 -12
  47. package/dist/runtime/components/Dropdown.vue.d.ts +33 -6
  48. package/dist/runtime/components/FileTree.d.vue.ts +2 -0
  49. package/dist/runtime/components/FileTree.vue +8 -4
  50. package/dist/runtime/components/FileTree.vue.d.ts +2 -0
  51. package/dist/runtime/components/FormField.d.vue.ts +4 -0
  52. package/dist/runtime/components/FormField.vue +19 -4
  53. package/dist/runtime/components/FormField.vue.d.ts +4 -0
  54. package/dist/runtime/components/Input.vue +3 -2
  55. package/dist/runtime/components/Kbd.vue +12 -2
  56. package/dist/runtime/components/Modal.vue +3 -2
  57. package/dist/runtime/components/NavigationMenu.d.vue.ts +10 -10
  58. package/dist/runtime/components/NavigationMenu.vue +13 -9
  59. package/dist/runtime/components/NavigationMenu.vue.d.ts +10 -10
  60. package/dist/runtime/components/NavigationMenuAccordionItem.vue +5 -1
  61. package/dist/runtime/components/NavigationMenuFlyoutList.vue +7 -4
  62. package/dist/runtime/components/Popover.d.vue.ts +8 -2
  63. package/dist/runtime/components/Popover.vue +13 -6
  64. package/dist/runtime/components/Popover.vue.d.ts +8 -2
  65. package/dist/runtime/components/ProsePre.d.vue.ts +2 -0
  66. package/dist/runtime/components/ProsePre.vue +2 -1
  67. package/dist/runtime/components/ProsePre.vue.d.ts +2 -0
  68. package/dist/runtime/components/Select.d.vue.ts +8 -4
  69. package/dist/runtime/components/Select.vue +4 -2
  70. package/dist/runtime/components/Select.vue.d.ts +8 -4
  71. package/dist/runtime/components/Slideover.vue +3 -2
  72. package/dist/runtime/components/SplitterPanel.d.vue.ts +2 -2
  73. package/dist/runtime/components/SplitterPanel.vue.d.ts +2 -2
  74. package/dist/runtime/components/Table.vue +95 -26
  75. package/dist/runtime/components/Tabs.d.vue.ts +44 -4
  76. package/dist/runtime/components/Tabs.vue +171 -18
  77. package/dist/runtime/components/Tabs.vue.d.ts +44 -4
  78. package/dist/runtime/components/Textarea.vue +3 -2
  79. package/dist/runtime/components/Timeline.d.vue.ts +19 -0
  80. package/dist/runtime/components/Timeline.vue +99 -0
  81. package/dist/runtime/components/Timeline.vue.d.ts +19 -0
  82. package/dist/runtime/components/Toast.d.vue.ts +10 -1
  83. package/dist/runtime/components/Toast.vue +94 -8
  84. package/dist/runtime/components/Toast.vue.d.ts +10 -1
  85. package/dist/runtime/components/Tooltip.d.vue.ts +8 -2
  86. package/dist/runtime/components/Tooltip.vue +13 -6
  87. package/dist/runtime/components/Tooltip.vue.d.ts +8 -2
  88. package/dist/runtime/composables/use-confirm.d.ts +14 -0
  89. package/dist/runtime/composables/use-confirm.js +28 -0
  90. package/dist/runtime/composables/use-form-field.d.ts +1 -0
  91. package/dist/runtime/composables/use-table.d.ts +3 -0
  92. package/dist/runtime/composables/use-table.js +10 -4
  93. package/dist/runtime/composables/use-toast.js +5 -1
  94. package/dist/runtime/directives/hotkey.d.ts +13 -0
  95. package/dist/runtime/directives/hotkey.js +107 -0
  96. package/dist/runtime/directives/index.d.ts +2 -0
  97. package/dist/runtime/directives/index.js +2 -0
  98. package/dist/runtime/directives/mask.d.ts +30 -0
  99. package/dist/runtime/directives/mask.js +165 -0
  100. package/dist/runtime/internal/ComboboxSelectBase.d.vue.ts +41 -36
  101. package/dist/runtime/internal/ComboboxSelectBase.vue +119 -26
  102. package/dist/runtime/internal/ComboboxSelectBase.vue.d.ts +41 -36
  103. package/dist/runtime/internal/ComboboxSelectBody.d.vue.ts +23 -17
  104. package/dist/runtime/internal/ComboboxSelectBody.vue +50 -11
  105. package/dist/runtime/internal/ComboboxSelectBody.vue.d.ts +23 -17
  106. package/dist/runtime/internal/DatePickerCalendarBody.vue +1 -1
  107. package/dist/runtime/internal/DatePickerRangeCalendarBody.vue +1 -1
  108. package/dist/runtime/internal/ShortcutHint.d.vue.ts +6 -0
  109. package/dist/runtime/internal/ShortcutHint.vue +13 -0
  110. package/dist/runtime/internal/ShortcutHint.vue.d.ts +6 -0
  111. package/dist/runtime/internal/ToastItemRenderer.d.vue.ts +9 -1
  112. package/dist/runtime/internal/ToastItemRenderer.vue +55 -8
  113. package/dist/runtime/internal/ToastItemRenderer.vue.d.ts +9 -1
  114. package/dist/runtime/internal/combobox-select.d.ts +19 -18
  115. package/dist/runtime/internal/combobox-select.js +38 -15
  116. package/dist/runtime/internal/programmatic-services.d.ts +13 -0
  117. package/dist/runtime/internal/programmatic-services.js +9 -0
  118. package/dist/runtime/internal/toast-stack.d.ts +36 -0
  119. package/dist/runtime/internal/toast-stack.js +36 -0
  120. package/dist/runtime/structural.css +1 -1
  121. package/dist/runtime/table.d.ts +1 -1
  122. package/dist/runtime/theme/alert-dialog.js +1 -1
  123. package/dist/runtime/theme/badge.d.ts +9 -0
  124. package/dist/runtime/theme/badge.js +2 -1
  125. package/dist/runtime/theme/button.d.ts +18 -0
  126. package/dist/runtime/theme/button.js +4 -1
  127. package/dist/runtime/theme/calendar.d.ts +86 -0
  128. package/dist/runtime/theme/calendar.js +19 -0
  129. package/dist/runtime/theme/callout.d.ts +0 -12
  130. package/dist/runtime/theme/callout.js +8 -8
  131. package/dist/runtime/theme/code-tree.js +1 -1
  132. package/dist/runtime/theme/command-palette.js +1 -1
  133. package/dist/runtime/theme/content-navigation.d.ts +3 -0
  134. package/dist/runtime/theme/content-navigation.js +1 -0
  135. package/dist/runtime/theme/drawer.js +1 -1
  136. package/dist/runtime/theme/dropdown.d.ts +21 -0
  137. package/dist/runtime/theme/dropdown.js +15 -2
  138. package/dist/runtime/theme/file-tree.js +1 -1
  139. package/dist/runtime/theme/form-field.d.ts +18 -0
  140. package/dist/runtime/theme/form-field.js +6 -1
  141. package/dist/runtime/theme/modal.js +1 -1
  142. package/dist/runtime/theme/slideover.js +1 -1
  143. package/dist/runtime/theme/table.d.ts +27 -0
  144. package/dist/runtime/theme/table.js +11 -2
  145. package/dist/runtime/theme/tabs.d.ts +87 -3
  146. package/dist/runtime/theme/tabs.js +46 -22
  147. package/dist/runtime/theme/timeline.d.ts +251 -0
  148. package/dist/runtime/theme/timeline.js +84 -0
  149. package/dist/runtime/theme/toast.d.ts +92 -0
  150. package/dist/runtime/theme/toast.js +29 -7
  151. package/dist/runtime/theme-config.d.ts +13 -2
  152. package/dist/runtime/types/index.d.ts +10 -2
  153. package/dist/runtime/utils/arrow.d.ts +21 -0
  154. package/dist/runtime/utils/arrow.js +10 -0
  155. package/dist/runtime/utils/autocomplete-contracts.d.ts +4 -4
  156. package/dist/runtime/utils/file-icons.js +3 -0
  157. package/dist/runtime/utils/icons.d.ts +2 -0
  158. package/dist/runtime/utils/icons.js +2 -0
  159. package/dist/runtime/utils/messages.d.ts +7 -0
  160. package/dist/runtime/utils/messages.js +7 -0
  161. package/dist/runtime/utils/navigation-menu.d.ts +7 -0
  162. package/dist/runtime/utils/navigation-menu.js +3 -0
  163. package/dist/runtime/utils/overlay.d.ts +17 -0
  164. package/dist/runtime/utils/overlay.js +7 -0
  165. package/dist/runtime/utils/select-contracts.d.ts +25 -11
  166. package/dist/runtime/utils/table-columns.js +1 -1
  167. package/dist/runtime/utils/table-contracts.d.ts +9 -1
  168. package/dist/runtime/utils/timeline-contracts.d.ts +42 -0
  169. package/dist/runtime/utils/timeline-contracts.js +0 -0
  170. package/dist/runtime/utils/ui.d.ts +11 -0
  171. package/dist/runtime/utils/ui.js +54 -1
  172. package/package.json +6 -5
@@ -0,0 +1,69 @@
1
+ import type { DateValue } from '@internationalized/date';
2
+ import type { CalendarThemeSlots } from '../theme/calendar.js';
3
+ import type { ColorRole } from '../utils/color-registry.js';
4
+ import type { UiProp } from '../utils/ui.js';
5
+ type __VLS_Slots = {
6
+ 'day'?: (props: CalendarDaySlotProps) => any;
7
+ /** Renders beside the date trigger within its grid cell. Safe for event links/buttons. */
8
+ 'day-details'?: (props: {
9
+ date: DateValue;
10
+ month: DateValue;
11
+ }) => any;
12
+ 'footer'?: () => any;
13
+ };
14
+ export interface CalendarProps {
15
+ modelValue?: DateValue;
16
+ defaultValue?: DateValue;
17
+ /** The displayed month when controlled independently of the selected date. */
18
+ placeholder?: DateValue;
19
+ defaultPlaceholder?: DateValue;
20
+ minValue?: DateValue;
21
+ maxValue?: DateValue;
22
+ isDateDisabled?: (date: DateValue) => boolean;
23
+ isDateUnavailable?: (date: DateValue) => boolean;
24
+ locale?: string;
25
+ numberOfMonths?: number;
26
+ pagedNavigation?: boolean;
27
+ weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
28
+ weekdayFormat?: 'narrow' | 'short' | 'long';
29
+ fixedWeeks?: boolean;
30
+ disableDaysOutsideCurrentView?: boolean;
31
+ preventDeselect?: boolean;
32
+ disabled?: boolean;
33
+ readonly?: boolean;
34
+ initialFocus?: boolean;
35
+ calendarLabel?: string;
36
+ color?: ColorRole;
37
+ activeColor?: ColorRole;
38
+ ui?: UiProp<CalendarThemeSlots>;
39
+ }
40
+ export interface CalendarEmits {
41
+ 'update:modelValue': [value: DateValue | undefined];
42
+ 'update:placeholder': [value: DateValue];
43
+ }
44
+ export interface CalendarDaySlotProps {
45
+ date: DateValue;
46
+ month: DateValue;
47
+ dayValue: string;
48
+ selected: boolean;
49
+ today: boolean;
50
+ disabled: boolean;
51
+ unavailable: boolean;
52
+ outsideView: boolean;
53
+ outsideVisibleView: boolean;
54
+ }
55
+ declare const __VLS_base: import("vue").DefineComponent<CalendarProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
56
+ "update:modelValue": (value: DateValue | undefined) => any;
57
+ "update:placeholder": (value: DateValue) => any;
58
+ }, string, import("vue").PublicProps, Readonly<CalendarProps> & Readonly<{
59
+ "onUpdate:modelValue"?: ((value: DateValue | undefined) => any) | undefined;
60
+ "onUpdate:placeholder"?: ((value: DateValue) => any) | undefined;
61
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
62
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
63
+ declare const _default: typeof __VLS_export;
64
+ export default _default;
65
+ type __VLS_WithSlots<T, S> = T & {
66
+ new (): {
67
+ $slots: S;
68
+ };
69
+ };
@@ -24,6 +24,13 @@ const iconName = computed(() => {
24
24
  return void 0;
25
25
  return props.icon ?? icons.value[DEFAULT_ICON[props.type ?? "note"]];
26
26
  });
27
+ const colorForType = {
28
+ note: "info",
29
+ tip: "success",
30
+ warning: "warning",
31
+ danger: "danger"
32
+ };
33
+ const effectiveColor = computed(() => colorForType[props.type ?? "note"]);
27
34
  const theme = useComponentTheme("callout", calloutTheme);
28
35
  const ui = computed(() => theme.value({ type: props.type }));
29
36
  const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root);
@@ -33,7 +40,7 @@ const titleProps = computed(() => resolveSlot(ui.value.title, props.ui?.title));
33
40
  </script>
34
41
 
35
42
  <template>
36
- <div v-bind="rootProps" role="note">
43
+ <div v-bind="rootProps" data-selaras-callout :data-selaras-color="effectiveColor" role="note">
37
44
  <Icon v-if="iconName" :name="iconName" v-bind="iconProps" />
38
45
  <div v-bind="contentProps">
39
46
  <p v-if="title || $slots.title" v-bind="titleProps">
@@ -45,3 +52,7 @@ const titleProps = computed(() => resolveSlot(ui.value.title, props.ui?.title));
45
52
  </div>
46
53
  </div>
47
54
  </template>
55
+
56
+ <style scoped>
57
+ [data-selaras-callout]:before{-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude}
58
+ </style>
@@ -1,6 +1,8 @@
1
1
  <script setup>
2
2
  import { cloneVNode, Comment, computed, Fragment, ref, Text, useSlots } from "vue";
3
3
  import { useMessages } from "../composables/use-messages";
4
+ import { resolveFileIcon } from "../utils/file-icons";
5
+ import ProsePre from "./ProsePre.vue";
4
6
  import Tabs from "./Tabs.vue";
5
7
  const slots = useSlots();
6
8
  const messages = useMessages();
@@ -22,15 +24,23 @@ function labelFor(child, index) {
22
24
  const props = child.props ?? {};
23
25
  return props.filename || props.language || messages.value.codeTabFallback(index + 1);
24
26
  }
27
+ function iconFor(child) {
28
+ const props = child.props ?? {};
29
+ return props.icon ?? resolveFileIcon(props.language, props.filename);
30
+ }
31
+ function cloneForTab(child) {
32
+ return cloneVNode(child, child.type === ProsePre ? { showHeader: false } : void 0);
33
+ }
25
34
  const tabItems = computed(() => children.value.map((child, index) => ({
26
35
  label: labelFor(child, index),
27
- value: String(index)
36
+ value: String(index),
37
+ icon: iconFor(child)
28
38
  })));
29
39
  const activeTab = ref("0");
30
40
  </script>
31
41
 
32
42
  <template>
33
- <Tabs v-model="activeTab" :items="tabItems">
43
+ <Tabs v-model="activeTab" :items="tabItems" variant="pill">
34
44
  <template v-for="(child, index) in children" :key="index" #[String(index)]>
35
45
  <!--
36
46
  cloneVNode is required, not optional: this vnode was captured from
@@ -40,7 +50,7 @@ const activeTab = ref("0");
40
50
  hydration-shape mismatch (Fragment vs text) the first time this
41
51
  panel mounts. Cloning gives it a fresh identity for its new spot.
42
52
  -->
43
- <component :is="() => cloneVNode(child)" />
53
+ <component :is="() => cloneForTab(child)" />
44
54
  </template>
45
55
  </Tabs>
46
56
  </template>
@@ -4,6 +4,8 @@ import type { FileTreeNode } from './FileTree.vue.js';
4
4
  export interface CodeTreeFile extends FileTreeNode {
5
5
  /** The file's content - read for a leaf node once selected, ignored for a directory. */
6
6
  code?: string;
7
+ /** Overrides the language inferred from the filename. */
8
+ language?: string;
7
9
  children?: CodeTreeFile[];
8
10
  }
9
11
  export interface CodeTreeProps {
@@ -21,6 +21,56 @@ function findFirstFile(nodes) {
21
21
  return void 0;
22
22
  }
23
23
  const selected = ref(findFirstFile(props.items));
24
+ const highlightedCode = ref("");
25
+ const languageByExtension = {
26
+ bash: "bash",
27
+ cjs: "javascript",
28
+ css: "css",
29
+ htm: "html",
30
+ html: "html",
31
+ js: "javascript",
32
+ jsx: "jsx",
33
+ json: "json",
34
+ jsonc: "jsonc",
35
+ md: "markdown",
36
+ mjs: "javascript",
37
+ mts: "typescript",
38
+ sh: "bash",
39
+ ts: "typescript",
40
+ tsx: "tsx",
41
+ vue: "vue",
42
+ yaml: "yaml",
43
+ yml: "yaml"
44
+ };
45
+ function languageFor(file) {
46
+ if (file.language)
47
+ return file.language;
48
+ const extension = file.name.split(".").pop()?.toLowerCase() ?? "";
49
+ return languageByExtension[extension] ?? "text";
50
+ }
51
+ watch(selected, async (file, _previous, onCleanup) => {
52
+ let stale = false;
53
+ onCleanup(() => {
54
+ stale = true;
55
+ });
56
+ highlightedCode.value = "";
57
+ if (!file?.code)
58
+ return;
59
+ try {
60
+ const { codeToHtml } = await import("shiki");
61
+ const html = await codeToHtml(file.code, {
62
+ lang: languageFor(file),
63
+ themes: { light: "github-light", dark: "github-dark" },
64
+ defaultColor: false
65
+ });
66
+ if (stale)
67
+ return;
68
+ highlightedCode.value = html.match(/<code(?:\s[^>]*)?>([\s\S]*?)<\/code>/)?.[1] ?? "";
69
+ } catch {
70
+ if (!stale)
71
+ highlightedCode.value = "";
72
+ }
73
+ }, { immediate: true });
24
74
  watch(() => props.items, () => {
25
75
  selected.value = findFirstFile(props.items);
26
76
  });
@@ -28,6 +78,7 @@ const messages = useMessages();
28
78
  const theme = useComponentTheme("codeTree", codeTreeTheme);
29
79
  const ui = computed(() => theme.value());
30
80
  const rootProps = useRootProps(() => ui.value.root, () => props.ui?.root);
81
+ const codeMode = computed(() => rootProps.value["data-selaras-mode"]);
31
82
  const treeProps = computed(() => resolveSlot(ui.value.tree, props.ui?.tree));
32
83
  const contentProps = computed(() => resolveSlot(ui.value.content, props.ui?.content));
33
84
  const preProps = computed(() => resolveSlot(ui.value.pre, props.ui?.pre));
@@ -47,7 +98,7 @@ const fileTreeUi = { root: "rounded-none border-0 bg-transparent p-0" };
47
98
  />
48
99
  </div>
49
100
  <div v-if="selected" v-bind="contentProps">
50
- <pre v-bind="preProps">{{ selected.code }}</pre>
101
+ <pre v-bind="preProps"><code v-if="highlightedCode" class="selaras-code-tree-code" :data-selaras-code-mode="codeMode" v-html="highlightedCode" /><code v-else>{{ selected.code }}</code></pre>
51
102
  </div>
52
103
  <div v-else v-bind="emptyProps">
53
104
  {{ messages.selectFile }}
@@ -4,6 +4,8 @@ import type { FileTreeNode } from './FileTree.vue.js';
4
4
  export interface CodeTreeFile extends FileTreeNode {
5
5
  /** The file's content - read for a leaf node once selected, ignored for a directory. */
6
6
  code?: string;
7
+ /** Overrides the language inferred from the filename. */
8
+ language?: string;
7
9
  children?: CodeTreeFile[];
8
10
  }
9
11
  export interface CodeTreeProps {
@@ -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
+ };
@@ -1,6 +1,8 @@
1
1
  import type { VariantProps } from 'tailwind-variants';
2
2
  import type { ColorPickerThemeSlots } from '../theme/color-picker.js';
3
+ import type { RoundedArrowConfig } from '../utils/arrow.js';
3
4
  import type { ColorRole } from '../utils/color-registry.js';
5
+ import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
4
6
  import type { UiProp } from '../utils/ui.js';
5
7
  import { colorPickerTheme } from '../theme/color-picker.js';
6
8
  type ColorPickerVariants = VariantProps<typeof colorPickerTheme>;
@@ -21,6 +23,12 @@ export interface ColorPickerProps {
21
23
  placeholder?: string;
22
24
  /** Opts into the picker's accessible small-screen modal presentation. */
23
25
  adaptive?: boolean;
26
+ /** Shows a pointer on the anchored picker; the adaptive modal has no arrow. */
27
+ arrow?: boolean | RoundedArrowConfig;
28
+ /** Positioning of the anchored picker (the adaptive modal uses its own layout). */
29
+ positioning?: OverlayPositioning;
30
+ /** Teleport target for the anchored picker, or `false` to render it inline. */
31
+ portal?: OverlayPortal;
24
32
  size?: ColorPickerVariants['size'];
25
33
  color?: ColorRole;
26
34
  ui?: UiProp<ColorPickerThemeSlots>;
@@ -1,14 +1,17 @@
1
1
  <script setup>
2
- import { ColorSwatch } from "reka-ui";
2
+ import { ColorSwatch, PopoverArrow, PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger } from "reka-ui";
3
3
  import { computed, getCurrentInstance, onMounted, onUnmounted, ref, watch } from "vue";
4
+ import { useFormField } from "../composables/use-form-field";
4
5
  import { useIsMobile } from "../composables/use-media-query";
5
6
  import { useMessages } from "../composables/use-messages";
6
7
  import ColorPickerBody from "../internal/ColorPickerBody.vue";
7
8
  import { colorPickerTheme } from "../theme/color-picker";
9
+ import { popoverTheme } from "../theme/popover";
10
+ import { arrowContentProps, arrowElementProps } from "../utils/arrow";
11
+ import { overlayPortalProps } from "../utils/overlay";
8
12
  import { resolveRegisteredColorRole } from "../utils/registered-colors";
9
13
  import { resolveSlot, useComponentTheme, useThemeBindings } from "../utils/ui";
10
14
  import Modal from "./Modal.vue";
11
- import Popover from "./Popover.vue";
12
15
  const props = defineProps({
13
16
  name: { type: String, required: false },
14
17
  form: { type: String, required: false },
@@ -21,12 +24,17 @@ const props = defineProps({
21
24
  swatches: { type: Array, required: false },
22
25
  placeholder: { type: String, required: false },
23
26
  adaptive: { type: Boolean, required: false },
27
+ arrow: { type: [Boolean, Object], required: false },
28
+ positioning: { type: Object, required: false },
29
+ portal: { type: [Boolean, String], required: false, skipCheck: true, default: void 0 },
24
30
  size: { type: null, required: false },
25
31
  color: { type: null, required: false },
26
32
  ui: { type: Object, required: false }
27
33
  });
28
34
  const emit = defineEmits(["update:open", "update:modelValue"]);
29
35
  const messages = useMessages();
36
+ const field = useFormField();
37
+ const formName = computed(() => props.name ?? field?.name);
30
38
  const instance = getCurrentInstance();
31
39
  const formAnchor = ref();
32
40
  const initialColor = props.defaultValue ?? "#000000";
@@ -104,55 +112,68 @@ const bodyProps = computed(() => ({
104
112
  swatchIndicatorProps: swatchIndicatorProps.value,
105
113
  colorRoleMarker: colorRoleMarker.value
106
114
  }));
107
- const popoverUi = computed(() => ({ content: resolveSlot(ui.value.content, props.ui?.content) }));
115
+ const popoverThemeFn = useComponentTheme("popover", popoverTheme);
116
+ const popoverUi = computed(() => popoverThemeFn.value());
117
+ const popoverContentProps = computed(() => ({
118
+ ...resolveSlot(popoverUi.value.content, resolveSlot(ui.value.content, props.ui?.content)),
119
+ ...arrowContentProps(props.arrow),
120
+ ...props.positioning
121
+ }));
122
+ const popoverArrowProps = computed(() => ({ ...resolveSlot(popoverUi.value.arrow, void 0), ...arrowElementProps(props.arrow) }));
123
+ const popoverPortalProps = computed(() => overlayPortalProps(props.portal));
108
124
  const adaptiveUi = computed(() => ({ content: "rounded-[var(--selaras-resolved-radius-md)]" }));
109
125
  const mobileContentProps = computed(() => resolveSlot(ui.value.mobileContent, props.ui?.mobileContent));
110
126
  </script>
111
127
 
112
128
  <template>
113
- <Popover v-if="!showMobileModal" :open="open" :ui="popoverUi" @update:open="onUpdateOpen">
114
- <button
115
- type="button"
116
- :disabled="disabled"
117
- :aria-label="messages.colorPicker"
118
- :data-selaras-color="colorRoleMarker"
119
- :data-selaras-theme="themeBindings['data-selaras-theme']"
120
- :data-selaras-mode="themeBindings['data-selaras-mode']"
121
- :style="themeBindings.style"
122
- v-bind="triggerProps"
123
- >
124
- <ColorSwatch :color="internalColor" v-bind="triggerSwatchProps" />
125
- <span v-bind="triggerValueProps">{{ internalColor }}</span>
126
- </button>
129
+ <!--
130
+ The root and trigger stay mounted for both presentations. Only the
131
+ content switches: the anchored panel is removed outright while the
132
+ adaptive Modal is showing, and the Modal returns focus to this same
133
+ trigger on close.
134
+ -->
135
+ <PopoverRoot :open="open" @update:open="onUpdateOpen">
136
+ <PopoverTrigger as-child>
137
+ <button
138
+ type="button"
139
+ :disabled="disabled"
140
+ :aria-label="messages.colorPicker"
141
+ :data-selaras-color="colorRoleMarker"
142
+ :data-selaras-theme="themeBindings['data-selaras-theme']"
143
+ :data-selaras-mode="themeBindings['data-selaras-mode']"
144
+ :style="themeBindings.style"
145
+ v-bind="triggerProps"
146
+ >
147
+ <ColorSwatch :color="internalColor" v-bind="triggerSwatchProps" />
148
+ <span v-bind="triggerValueProps">{{ internalColor }}</span>
149
+ </button>
150
+ </PopoverTrigger>
127
151
 
128
- <template #content>
129
- <ColorPickerBody v-bind="bodyProps" @update:model-value="onUpdateColor" />
130
- </template>
131
- </Popover>
152
+ <PopoverPortal v-if="!showMobileModal" v-bind="popoverPortalProps">
153
+ <PopoverContent
154
+ :data-selaras-theme="themeBindings['data-selaras-theme']"
155
+ :data-selaras-mode="themeBindings['data-selaras-mode']"
156
+ :style="themeBindings.style"
157
+ side="bottom"
158
+ align="start"
159
+ :side-offset="8"
160
+ v-bind="popoverContentProps"
161
+ >
162
+ <ColorPickerBody v-bind="bodyProps" @update:model-value="onUpdateColor" />
163
+ <PopoverArrow v-if="arrow" v-bind="popoverArrowProps" />
164
+ </PopoverContent>
165
+ </PopoverPortal>
132
166
 
133
- <Modal
134
- v-else :open="open" :title="messages.colorPicker" :description="messages.colorPickerDescription"
135
- :ui="adaptiveUi" @update:open="onUpdateOpen"
136
- >
137
- <button
138
- type="button"
139
- :disabled="disabled"
140
- :aria-label="messages.colorPicker"
141
- :data-selaras-color="colorRoleMarker"
142
- :data-selaras-theme="themeBindings['data-selaras-theme']"
143
- :data-selaras-mode="themeBindings['data-selaras-mode']"
144
- :style="themeBindings.style"
145
- v-bind="triggerProps"
167
+ <Modal
168
+ v-else :open="open" :title="messages.colorPicker" :description="messages.colorPickerDescription"
169
+ :ui="adaptiveUi" @update:open="onUpdateOpen"
146
170
  >
147
- <ColorSwatch :color="internalColor" v-bind="triggerSwatchProps" />
148
- <span v-bind="triggerValueProps">{{ internalColor }}</span>
149
- </button>
150
-
151
- <template #content>
152
- <div v-bind="mobileContentProps">
153
- <ColorPickerBody v-bind="bodyProps" @update:model-value="onUpdateColor" />
154
- </div>
155
- </template>
156
- </Modal>
157
- <input ref="formAnchor" type="hidden" :name="name" :form="form" :value="internalColor">
171
+ <template #content>
172
+ <div v-bind="mobileContentProps">
173
+ <ColorPickerBody v-bind="bodyProps" @update:model-value="onUpdateColor" />
174
+ </div>
175
+ </template>
176
+ </Modal>
177
+ </PopoverRoot>
178
+ <input ref="formAnchor" type="hidden" :name="formName" :form="form" :value="internalColor" :disabled="disabled">
158
179
  </template>
@@ -1,6 +1,8 @@
1
1
  import type { VariantProps } from 'tailwind-variants';
2
2
  import type { ColorPickerThemeSlots } from '../theme/color-picker.js';
3
+ import type { RoundedArrowConfig } from '../utils/arrow.js';
3
4
  import type { ColorRole } from '../utils/color-registry.js';
5
+ import type { OverlayPortal, OverlayPositioning } from '../utils/overlay.js';
4
6
  import type { UiProp } from '../utils/ui.js';
5
7
  import { colorPickerTheme } from '../theme/color-picker.js';
6
8
  type ColorPickerVariants = VariantProps<typeof colorPickerTheme>;
@@ -21,6 +23,12 @@ export interface ColorPickerProps {
21
23
  placeholder?: string;
22
24
  /** Opts into the picker's accessible small-screen modal presentation. */
23
25
  adaptive?: boolean;
26
+ /** Shows a pointer on the anchored picker; the adaptive modal has no arrow. */
27
+ arrow?: boolean | RoundedArrowConfig;
28
+ /** Positioning of the anchored picker (the adaptive modal uses its own layout). */
29
+ positioning?: OverlayPositioning;
30
+ /** Teleport target for the anchored picker, or `false` to render it inline. */
31
+ portal?: OverlayPortal;
24
32
  size?: ColorPickerVariants['size'];
25
33
  color?: ColorRole;
26
34
  ui?: UiProp<ColorPickerThemeSlots>;
@@ -16,7 +16,7 @@ export default defineComponent({
16
16
  },
17
17
  sortable: {
18
18
  type: Boolean,
19
- default: true
19
+ default: false
20
20
  },
21
21
  filterable: {
22
22
  type: Boolean,
@@ -3,8 +3,10 @@ import type { UiProp } from '../utils/ui.js';
3
3
  export interface CommandPaletteItem {
4
4
  label: string;
5
5
  icon?: string;
6
- /** Rendered via Kbd - a display hint only, this component doesn't bind the key itself. */
6
+ /** Displayed via Kbd. */
7
7
  shortcut?: string;
8
+ /** Bind `shortcut` while this palette is open; activation uses this item's normal selection behavior. */
9
+ hotkey?: boolean;
8
10
  disabled?: boolean;
9
11
  onSelect?: () => void;
10
12
  }
@@ -4,6 +4,7 @@ import { computed, onMounted, onUnmounted, ref, useId, watch } from "vue";
4
4
  import { useCommandPalette } from "../composables/use-command-palette";
5
5
  import { useIcons } from "../composables/use-icons";
6
6
  import { useMessages } from "../composables/use-messages";
7
+ import { vHotkey } from "../directives/hotkey";
7
8
  import { commandPaletteTheme } from "../theme/command-palette";
8
9
  import { fuzzyScore } from "../utils/fuzzy-match";
9
10
  import { applyClassPrefix, resolveSlot, useComponentTheme, useRootProps, useThemeBindings } from "../utils/ui";
@@ -40,6 +41,9 @@ const query = ref("");
40
41
  const highlightedIndex = ref(0);
41
42
  const inputRef = ref();
42
43
  const listboxId = `selaras-command-palette-list-${useId()}`;
44
+ function hotkeyFor(item) {
45
+ return item.hotkey && item.shortcut && !item.disabled ? { keys: item.shortcut, when: () => isOpen.value, allowInEditable: true } : void 0;
46
+ }
43
47
  watch(isOpen, (open) => {
44
48
  if (!open) {
45
49
  query.value = "";
@@ -178,6 +182,7 @@ function itemId(index) {
178
182
  v-for="item in group.items"
179
183
  :id="itemId(allItems.indexOf(item))"
180
184
  :key="item.label"
185
+ v-hotkey="hotkeyFor(item)"
181
186
  role="option"
182
187
  :aria-selected="isHighlighted(item)"
183
188
  :aria-disabled="item.disabled"
@@ -3,8 +3,10 @@ import type { UiProp } from '../utils/ui.js';
3
3
  export interface CommandPaletteItem {
4
4
  label: string;
5
5
  icon?: string;
6
- /** Rendered via Kbd - a display hint only, this component doesn't bind the key itself. */
6
+ /** Displayed via Kbd. */
7
7
  shortcut?: string;
8
+ /** Bind `shortcut` while this palette is open; activation uses this item's normal selection behavior. */
9
+ hotkey?: boolean;
8
10
  disabled?: boolean;
9
11
  onSelect?: () => void;
10
12
  }
@@ -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;