@rio-m3e/vue 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -8,4 +8,6 @@ pnpm add @rio-m3e/vue @rio-m3e/tokens
8
8
 
9
9
  Apply the theme from `@rio-m3e/tokens` once, then use the components. Each component imports its own styles. See the [README](https://github.com/LegenLee/rio#usage) for setup and [docs/components](https://github.com/LegenLee/rio/tree/main/docs/components) for each component.
10
10
 
11
+ You can see the document page in [here](https://legenlee.github.io/rio/).
12
+
11
13
  Licensed under the Apache License 2.0.
@@ -10,11 +10,11 @@ type __VLS_Slots = {
10
10
  icon?: () => unknown;
11
11
  };
12
12
  declare const __VLS_base: import("vue").DefineComponent<ButtonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
- "update:selected": (selected: boolean) => any;
14
13
  click: (event: MouseEvent) => any;
14
+ "update:selected": (selected: boolean) => any;
15
15
  }, string, import("vue").PublicProps, Readonly<ButtonProps> & Readonly<{
16
- "onUpdate:selected"?: ((selected: boolean) => any) | undefined;
17
16
  onClick?: ((event: MouseEvent) => any) | undefined;
17
+ "onUpdate:selected"?: ((selected: boolean) => any) | undefined;
18
18
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
19
19
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
20
20
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,37 @@
1
+ import { DialogCancelEvent, DialogProps } from "@rio-m3e/core";
2
+ import "@rio-m3e/styles/base/focus-ring.css";
3
+ import "@rio-m3e/styles/base/reduced-motion.css";
4
+ import "@rio-m3e/styles/dialog.css";
5
+ interface Props extends Omit<DialogProps, 'open'> {
6
+ /** States what the dialog is for, and names it. Without it, give the dialog an `aria-label`. */
7
+ headline?: string;
8
+ }
9
+ type __VLS_Props = Props;
10
+ type __VLS_Slots = {
11
+ /** The supporting text, or a list or a form */
12
+ default?: () => unknown;
13
+ /** An icon above the headline, which centers both */
14
+ icon?: () => unknown;
15
+ /** Up to two buttons: the dismissing one first, then the confirming one. */
16
+ actions?: () => unknown;
17
+ };
18
+ type __VLS_ModelProps = {
19
+ /** Whether the dialog is shown, with `v-model:open`. */
20
+ 'open'?: boolean;
21
+ };
22
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
23
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
24
+ "update:open": (value: boolean) => any;
25
+ cancel: (event: DialogCancelEvent) => any;
26
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
27
+ "onUpdate:open"?: ((value: boolean) => any) | undefined;
28
+ onCancel?: ((event: DialogCancelEvent) => 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
+ type __VLS_WithSlots<T, S> = T & {
33
+ new (): {
34
+ $slots: S;
35
+ };
36
+ };
37
+ export { _default as default };
@@ -0,0 +1,73 @@
1
+ import { Fragment, createCommentVNode, createElementBlock, createElementVNode, defineComponent, guardReactiveProps, mergeModels, mergeProps, normalizeProps, onBeforeUnmount, onMounted, onUpdated, openBlock, ref, renderSlot, toDisplayString, unref, useId, useModel, useSlots, useTemplateRef, watch } from "vue";
2
+ import { attachDialog, createDialog } from "@rio-m3e/core";
3
+ import "@rio-m3e/styles/base/focus-ring.css";
4
+ import "@rio-m3e/styles/base/reduced-motion.css";
5
+ import "@rio-m3e/styles/dialog.css";
6
+ // src/dialog/Dialog.vue
7
+ const _sfc_main = /*@__PURE__*/ defineComponent({
8
+ __name: "Dialog",
9
+ props: /*@__PURE__*/ mergeModels({
10
+ headline: {},
11
+ role: {}
12
+ }, {
13
+ "open": {
14
+ type: Boolean,
15
+ default: false
16
+ },
17
+ "openModifiers": {}
18
+ }),
19
+ emits: /*@__PURE__*/ mergeModels(["cancel"], ["update:open"]),
20
+ setup(__props, { emit: __emit }) {
21
+ /** Whether the dialog is shown, with `v-model:open`. */
22
+ const open = useModel(__props, "open");
23
+ const emit = __emit;
24
+ const slots = useSlots();
25
+ const id = useId();
26
+ const dialog = createDialog({
27
+ props: () => ({
28
+ open: open.value,
29
+ role: __props.role
30
+ }),
31
+ content: () => ({
32
+ icon: !!slots.icon,
33
+ headline: !!__props.headline,
34
+ actions: !!slots.actions
35
+ }),
36
+ ids: {
37
+ headline: `${id}-headline`,
38
+ content: `${id}-content`
39
+ }
40
+ });
41
+ const rendered = ref(open.value);
42
+ watch(open, (next) => {
43
+ if (next) rendered.value = true;
44
+ });
45
+ const root = useTemplateRef("root");
46
+ let handle;
47
+ onMounted(() => {
48
+ handle = attachDialog(root.value, {
49
+ onCancel: (event) => emit("cancel", event),
50
+ onOpenChange: (next) => open.value = next,
51
+ onClosed: () => {
52
+ if (!open.value) rendered.value = false;
53
+ }
54
+ });
55
+ handle.sync(open.value);
56
+ });
57
+ watch(open, (next) => handle?.sync(next), { flush: "post" });
58
+ onUpdated(() => handle?.update());
59
+ onBeforeUnmount(() => handle?.detach());
60
+ return (_ctx, _cache) => {
61
+ return openBlock(), createElementBlock("dialog", mergeProps({
62
+ ref_key: "root",
63
+ ref: root
64
+ }, unref(dialog).parts.root()), [rendered.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
65
+ unref(dialog).showsIcon() ? (openBlock(), createElementBlock("div", normalizeProps(mergeProps({ key: 0 }, unref(dialog).parts.icon())), [renderSlot(_ctx.$slots, "icon")], 16)) : createCommentVNode("v-if", true),
66
+ unref(dialog).showsHeadline() ? (openBlock(), createElementBlock("h2", normalizeProps(mergeProps({ key: 1 }, unref(dialog).parts.headline())), toDisplayString(__props.headline), 17)) : createCommentVNode("v-if", true),
67
+ createElementVNode("div", normalizeProps(guardReactiveProps(unref(dialog).parts.content())), [renderSlot(_ctx.$slots, "default")], 16),
68
+ unref(dialog).showsActions() ? (openBlock(), createElementBlock("div", normalizeProps(mergeProps({ key: 2 }, unref(dialog).parts.actions())), [renderSlot(_ctx.$slots, "actions")], 16)) : createCommentVNode("v-if", true)
69
+ ], 64)) : createCommentVNode("v-if", true)], 16);
70
+ };
71
+ }
72
+ });
73
+ export { _sfc_main as default };
@@ -8,17 +8,17 @@ type __VLS_Slots = {
8
8
  /** The icon. Hidden from assistive technology; `label` names the button. */
9
9
  default?: () => unknown;
10
10
  /**
11
- * The icon while a toggle button is on, typically the filled version of the default icon. The
12
- * spec asks for selection to show in more than color alone.
11
+ * The icon while a toggle button is on, typically the filled version of the default icon, so
12
+ * the selection shows in more than color alone.
13
13
  */
14
14
  'selected-icon'?: () => unknown;
15
15
  };
16
16
  declare const __VLS_base: import("vue").DefineComponent<IconButtonProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
17
- "update:selected": (selected: boolean) => any;
18
17
  click: (event: MouseEvent) => any;
18
+ "update:selected": (selected: boolean) => any;
19
19
  }, string, import("vue").PublicProps, Readonly<IconButtonProps> & Readonly<{
20
- "onUpdate:selected"?: ((selected: boolean) => any) | undefined;
21
20
  onClick?: ((event: MouseEvent) => any) | undefined;
21
+ "onUpdate:selected"?: ((selected: boolean) => any) | undefined;
22
22
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
23
23
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
24
24
  declare const _default: typeof __VLS_export;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  import _default from "./button/Button.vue.js";
2
2
  import _default$1 from "./button-group/ButtonGroup.vue.js";
3
- import _default$2 from "./icon-button/IconButton.vue.js";
3
+ import _default$2 from "./dialog/Dialog.vue.js";
4
+ import _default$3 from "./icon-button/IconButton.vue.js";
5
+ import _default$4 from "./menu/Menu.vue.js";
6
+ import _default$5 from "./menu/MenuDivider.vue.js";
7
+ import _default$6 from "./menu/MenuGroup.vue.js";
8
+ import _default$7 from "./menu/MenuItem.vue.js";
9
+ import _default$9 from "./menu/SubMenu.vue.js";
4
10
  import { vRipple } from "./ripple/ripple.js";
5
- import _default$3 from "./split-button/SplitButton.vue.js";
6
- import _default$4 from "./switch/Switch.vue.js";
7
- export { _default as RioButton, _default$1 as RioButtonGroup, _default$2 as RioIconButton, _default$3 as RioSplitButton, _default$4 as RioSwitch, vRipple };
11
+ import _default$8 from "./split-button/SplitButton.vue.js";
12
+ import _default$10 from "./switch/Switch.vue.js";
13
+ import _default$11 from "./tooltip/Tooltip.vue.js";
14
+ export { _default as RioButton, _default$1 as RioButtonGroup, _default$2 as RioDialog, _default$3 as RioIconButton, _default$4 as RioMenu, _default$5 as RioMenuDivider, _default$6 as RioMenuGroup, _default$7 as RioMenuItem, _default$8 as RioSplitButton, _default$9 as RioSubMenu, _default$10 as RioSwitch, _default$11 as RioTooltip, vRipple };
package/dist/index.js CHANGED
@@ -1,7 +1,14 @@
1
1
  import _sfc_main from "./button/Button.vue.js";
2
2
  import _sfc_main$1 from "./button-group/ButtonGroup.vue.js";
3
- import _sfc_main$2 from "./icon-button/IconButton.vue.js";
3
+ import _sfc_main$2 from "./dialog/Dialog.vue.js";
4
+ import _sfc_main$3 from "./icon-button/IconButton.vue.js";
5
+ import _sfc_main$4 from "./menu/Menu.vue.js";
6
+ import _sfc_main$5 from "./menu/MenuDivider.vue.js";
7
+ import _sfc_main$6 from "./menu/MenuGroup.vue.js";
8
+ import _sfc_main$7 from "./menu/MenuItem.vue.js";
9
+ import _sfc_main$9 from "./menu/SubMenu.vue.js";
4
10
  import { vRipple } from "./ripple/ripple.js";
5
- import _sfc_main$3 from "./split-button/SplitButton.vue.js";
6
- import _sfc_main$4 from "./switch/Switch.vue.js";
7
- export { _sfc_main as RioButton, _sfc_main$1 as RioButtonGroup, _sfc_main$2 as RioIconButton, _sfc_main$3 as RioSplitButton, _sfc_main$4 as RioSwitch, vRipple };
11
+ import _sfc_main$8 from "./split-button/SplitButton.vue.js";
12
+ import _sfc_main$10 from "./switch/Switch.vue.js";
13
+ import _sfc_main$11 from "./tooltip/Tooltip.vue.js";
14
+ export { _sfc_main as RioButton, _sfc_main$1 as RioButtonGroup, _sfc_main$2 as RioDialog, _sfc_main$3 as RioIconButton, _sfc_main$4 as RioMenu, _sfc_main$5 as RioMenuDivider, _sfc_main$6 as RioMenuGroup, _sfc_main$7 as RioMenuItem, _sfc_main$8 as RioSplitButton, _sfc_main$9 as RioSubMenu, _sfc_main$10 as RioSwitch, _sfc_main$11 as RioTooltip, vRipple };
@@ -0,0 +1,35 @@
1
+ import { MenuAnchorPoint, MenuProps, MenuSelected } from "@rio-m3e/core";
2
+ import "@rio-m3e/styles/base/reduced-motion.css";
3
+ import "@rio-m3e/styles/base/anchored-position.css";
4
+ import "@rio-m3e/styles/menu.css";
5
+ interface Props extends Omit<MenuProps, 'selected'> {
6
+ /**
7
+ * What the menu opens from: an element or a component, such as the button that opens it (its
8
+ * template ref), or a point in viewport coordinates, for a context menu. Give the point the
9
+ * `element` it is on, and the menu keeps to that spot on it as it scrolls.
10
+ */
11
+ anchor?: HTMLElement | {
12
+ readonly $el: unknown;
13
+ } | MenuAnchorPoint | null;
14
+ /** The selected value (`single`) or values (`multiple`), with `v-model`. */
15
+ modelValue?: MenuSelected;
16
+ }
17
+ type __VLS_Slots = {
18
+ /** `RioMenuItem`s, `RioMenuDivider`s, and `RioMenuGroup`s */
19
+ default?: () => unknown;
20
+ };
21
+ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
22
+ "update:open": (open: boolean) => any;
23
+ "update:modelValue": (selected: MenuSelected) => any;
24
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
25
+ "onUpdate:open"?: ((open: boolean) => any) | undefined;
26
+ "onUpdate:modelValue"?: ((selected: MenuSelected) => any) | undefined;
27
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
+ declare const _default: typeof __VLS_export;
30
+ type __VLS_WithSlots<T, S> = T & {
31
+ new (): {
32
+ $slots: S;
33
+ };
34
+ };
35
+ export { _default as default };
@@ -0,0 +1,76 @@
1
+ import { menuContextOf, menuKey } from "./context.js";
2
+ import { createElementBlock, defineComponent, mergeProps, onBeforeUnmount, onMounted, openBlock, provide, renderSlot, unref, useTemplateRef, watch } from "vue";
3
+ import { attachMenu, createMenu } from "@rio-m3e/core";
4
+ import "@rio-m3e/styles/base/reduced-motion.css";
5
+ import "@rio-m3e/styles/base/anchored-position.css";
6
+ import "@rio-m3e/styles/menu.css";
7
+ // src/menu/Menu.vue
8
+ const _sfc_main = /*@__PURE__*/ defineComponent({
9
+ __name: "Menu",
10
+ props: {
11
+ anchor: {},
12
+ modelValue: {},
13
+ open: { type: Boolean },
14
+ variant: {},
15
+ selection: {},
16
+ label: {},
17
+ side: {},
18
+ align: {},
19
+ offset: {},
20
+ instant: { type: Boolean }
21
+ },
22
+ emits: ["update:open", "update:modelValue"],
23
+ setup(__props, { emit: __emit }) {
24
+ const emit = __emit;
25
+ const menu = createMenu({
26
+ props: () => ({
27
+ open: __props.open,
28
+ variant: __props.variant,
29
+ selection: __props.selection,
30
+ selected: __props.modelValue,
31
+ label: __props.label,
32
+ side: __props.side,
33
+ align: __props.align,
34
+ offset: __props.offset,
35
+ instant: __props.instant
36
+ }),
37
+ onChange: (selected) => emit("update:modelValue", selected),
38
+ onOpenChange: (next) => emit("update:open", next)
39
+ });
40
+ provide(menuKey, menuContextOf(menu));
41
+ /** A component's root element, or the element or point itself */
42
+ const anchorTarget = () => __props.anchor && "$el" in __props.anchor ? __props.anchor.$el : __props.anchor ?? void 0;
43
+ const root = useTemplateRef("root");
44
+ let handle;
45
+ onMounted(() => {
46
+ handle = attachMenu(root.value, {
47
+ anchor: anchorTarget,
48
+ props: () => ({
49
+ side: __props.side,
50
+ align: __props.align,
51
+ offset: __props.offset
52
+ }),
53
+ onClose: () => emit("update:open", false)
54
+ });
55
+ handle.sync(!!__props.open);
56
+ });
57
+ watch(() => __props.open, (next) => handle?.sync(!!next), { flush: "post" });
58
+ const pointOf = () => {
59
+ const target = anchorTarget();
60
+ return target && "x" in target && "y" in target && !("getBoundingClientRect" in target) ? target : void 0;
61
+ };
62
+ const anchorKey = () => {
63
+ const point = pointOf();
64
+ return point ? `${point.x},${point.y}` : anchorTarget();
65
+ };
66
+ watch([anchorKey, () => pointOf()?.element], () => handle?.update(), { flush: "post" });
67
+ onBeforeUnmount(() => handle?.detach());
68
+ return (_ctx, _cache) => {
69
+ return openBlock(), createElementBlock("div", mergeProps({
70
+ ref_key: "root",
71
+ ref: root
72
+ }, unref(menu).parts.root()), [renderSlot(_ctx.$slots, "default")], 16);
73
+ };
74
+ }
75
+ });
76
+ export { _sfc_main as default };
@@ -0,0 +1,4 @@
1
+ import "@rio-m3e/styles/menu.css";
2
+ 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>;
3
+ declare const _default: typeof __VLS_export;
4
+ export { _default as default };
@@ -0,0 +1,14 @@
1
+ import { createElementBlock, defineComponent, guardReactiveProps, normalizeProps, openBlock, unref } from "vue";
2
+ import { createMenuDivider } from "@rio-m3e/core";
3
+ import "@rio-m3e/styles/menu.css";
4
+ // src/menu/MenuDivider.vue
5
+ const _sfc_main = /*@__PURE__*/ defineComponent({
6
+ __name: "MenuDivider",
7
+ setup(__props) {
8
+ const divider = createMenuDivider();
9
+ return (_ctx, _cache) => {
10
+ return openBlock(), createElementBlock("div", normalizeProps(guardReactiveProps(unref(divider).parts.root())), null, 16);
11
+ };
12
+ }
13
+ });
14
+ export { _sfc_main as default };
@@ -0,0 +1,15 @@
1
+ import { MenuGroupProps } from "@rio-m3e/core";
2
+ import "@rio-m3e/styles/menu.css";
3
+ type __VLS_Slots = {
4
+ /** The group's `RioMenuItem`s */
5
+ default?: () => unknown;
6
+ };
7
+ declare const __VLS_base: import("vue").DefineComponent<MenuGroupProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<MenuGroupProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
8
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
9
+ declare const _default: typeof __VLS_export;
10
+ type __VLS_WithSlots<T, S> = T & {
11
+ new (): {
12
+ $slots: S;
13
+ };
14
+ };
15
+ export { _default as default };
@@ -0,0 +1,15 @@
1
+ import { createCommentVNode, createElementBlock, createElementVNode, defineComponent, guardReactiveProps, mergeProps, normalizeProps, openBlock, renderSlot, toDisplayString, unref } from "vue";
2
+ import { createMenuGroup } from "@rio-m3e/core";
3
+ import "@rio-m3e/styles/menu.css";
4
+ // src/menu/MenuGroup.vue
5
+ const _sfc_main = /*@__PURE__*/ defineComponent({
6
+ __name: "MenuGroup",
7
+ props: { label: {} },
8
+ setup(__props) {
9
+ const group = createMenuGroup({ props: () => ({ label: __props.label }) });
10
+ return (_ctx, _cache) => {
11
+ return openBlock(), createElementBlock("div", normalizeProps(guardReactiveProps(unref(group).parts.root())), [unref(group).showsLabel() ? (openBlock(), createElementBlock("div", normalizeProps(mergeProps({ key: 0 }, unref(group).parts.label())), toDisplayString(__props.label), 17)) : createCommentVNode("v-if", true), createElementVNode("div", normalizeProps(guardReactiveProps(unref(group).parts.items())), [renderSlot(_ctx.$slots, "default")], 16)], 16);
12
+ };
13
+ }
14
+ });
15
+ export { _sfc_main as default };
@@ -0,0 +1,34 @@
1
+ import { MenuItemProps } from "@rio-m3e/core";
2
+ import "@rio-m3e/styles/base/focus-ring.css";
3
+ import "@rio-m3e/styles/base/state-layer.css";
4
+ import "@rio-m3e/styles/menu.css";
5
+ type __VLS_Slots = {
6
+ /** The label */
7
+ default?: () => unknown;
8
+ /**
9
+ * A leading icon, hidden from assistive technology. In a selecting menu, `selected` lets it show
10
+ * a check mark next to the color and shape.
11
+ */
12
+ icon?: (props: {
13
+ selected: boolean;
14
+ }) => unknown;
15
+ /** Supporting text under the label */
16
+ 'supporting-text'?: () => unknown;
17
+ /** Trailing text, such as a keyboard shortcut */
18
+ 'trailing-text'?: () => unknown;
19
+ /** A trailing icon, hidden from assistive technology */
20
+ 'trailing-icon'?: () => unknown;
21
+ };
22
+ declare const __VLS_base: import("vue").DefineComponent<MenuItemProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
23
+ click: (event: MouseEvent) => any;
24
+ }, string, import("vue").PublicProps, Readonly<MenuItemProps> & Readonly<{
25
+ onClick?: ((event: MouseEvent) => any) | undefined;
26
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
28
+ declare const _default: typeof __VLS_export;
29
+ type __VLS_WithSlots<T, S> = T & {
30
+ new (): {
31
+ $slots: S;
32
+ };
33
+ };
34
+ export { _default as default };
@@ -0,0 +1,45 @@
1
+ import { vRipple } from "../ripple/ripple.js";
2
+ import { menuKey } from "./context.js";
3
+ import { createCommentVNode, createElementBlock, createElementVNode, defineComponent, guardReactiveProps, inject, mergeProps, normalizeProps, openBlock, renderSlot, unref, useSlots, withDirectives } from "vue";
4
+ import { createMenuItem } from "@rio-m3e/core";
5
+ import "@rio-m3e/styles/base/focus-ring.css";
6
+ import "@rio-m3e/styles/base/state-layer.css";
7
+ import "@rio-m3e/styles/menu.css";
8
+ // src/menu/MenuItem.vue
9
+ const _sfc_main = /*@__PURE__*/ defineComponent({
10
+ __name: "MenuItem",
11
+ props: {
12
+ value: {},
13
+ disabled: { type: Boolean }
14
+ },
15
+ emits: ["click"],
16
+ setup(__props, { emit: __emit }) {
17
+ const emit = __emit;
18
+ const slots = useSlots();
19
+ const menu = inject(menuKey, void 0);
20
+ const item = createMenuItem({
21
+ props: () => ({
22
+ value: __props.value,
23
+ disabled: __props.disabled
24
+ }),
25
+ content: () => ({
26
+ icon: !!slots.icon,
27
+ supportingText: !!slots["supporting-text"],
28
+ trailingText: !!slots["trailing-text"],
29
+ trailingIcon: !!slots["trailing-icon"]
30
+ }),
31
+ menu: () => menu,
32
+ onClick: (event) => emit("click", event)
33
+ });
34
+ return (_ctx, _cache) => {
35
+ return withDirectives((openBlock(), createElementBlock("button", mergeProps(unref(item).parts.root(), { onClick: _cache[0] || (_cache[0] = (...args) => unref(item).handleClick && unref(item).handleClick(...args)) }), [
36
+ createElementVNode("span", normalizeProps(guardReactiveProps(unref(item).parts.touch())), null, 16),
37
+ unref(item).showsIcon() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 0 }, unref(item).parts.icon())), [renderSlot(_ctx.$slots, "icon", { selected: unref(item).selected() })], 16)) : createCommentVNode("v-if", true),
38
+ createElementVNode("span", normalizeProps(guardReactiveProps(unref(item).parts.text())), [createElementVNode("span", normalizeProps(guardReactiveProps(unref(item).parts.label())), [renderSlot(_ctx.$slots, "default")], 16), unref(item).showsSupportingText() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 0 }, unref(item).parts.supportingText())), [renderSlot(_ctx.$slots, "supporting-text")], 16)) : createCommentVNode("v-if", true)], 16),
39
+ unref(item).showsTrailingText() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 1 }, unref(item).parts.trailingText())), [renderSlot(_ctx.$slots, "trailing-text")], 16)) : createCommentVNode("v-if", true),
40
+ unref(item).showsTrailingIcon() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 2 }, unref(item).parts.trailingIcon())), [renderSlot(_ctx.$slots, "trailing-icon")], 16)) : createCommentVNode("v-if", true)
41
+ ], 16)), [[unref(vRipple)]]);
42
+ };
43
+ }
44
+ });
45
+ export { _sfc_main as default };
@@ -0,0 +1,38 @@
1
+ import { MenuSelected, SubMenuProps } from "@rio-m3e/core";
2
+ import "@rio-m3e/styles/base/focus-ring.css";
3
+ import "@rio-m3e/styles/base/reduced-motion.css";
4
+ import "@rio-m3e/styles/base/state-layer.css";
5
+ import "@rio-m3e/styles/base/anchored-position.css";
6
+ import "@rio-m3e/styles/menu.css";
7
+ interface Props extends Omit<SubMenuProps, 'selected'> {
8
+ /** The selected value (`single`) or values (`multiple`), with `v-model`. */
9
+ modelValue?: MenuSelected;
10
+ }
11
+ type __VLS_Slots = {
12
+ /** The submenu's `RioMenuItem`s, `RioMenuDivider`s, `RioMenuGroup`s, and `RioSubMenu`s */
13
+ default?: () => unknown;
14
+ /** A leading icon on the item, hidden from assistive technology */
15
+ icon?: () => unknown;
16
+ /** Supporting text under the item's label */
17
+ 'supporting-text'?: () => unknown;
18
+ /** Trailing text on the item */
19
+ 'trailing-text'?: () => unknown;
20
+ /**
21
+ * A trailing icon on the item, hidden from assistive technology, such as an arrow pointing to the
22
+ * submenu. Rio ships no icons.
23
+ */
24
+ 'trailing-icon'?: () => unknown;
25
+ };
26
+ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
27
+ "update:modelValue": (selected: MenuSelected) => any;
28
+ }, string, import("vue").PublicProps, Readonly<Props> & Readonly<{
29
+ "onUpdate:modelValue"?: ((selected: MenuSelected) => any) | undefined;
30
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
31
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
32
+ declare const _default: typeof __VLS_export;
33
+ type __VLS_WithSlots<T, S> = T & {
34
+ new (): {
35
+ $slots: S;
36
+ };
37
+ };
38
+ export { _default as default };
@@ -0,0 +1,72 @@
1
+ import { vRipple } from "../ripple/ripple.js";
2
+ import { menuContextOf, menuKey } from "./context.js";
3
+ import { Fragment, createCommentVNode, createElementBlock, createElementVNode, defineComponent, guardReactiveProps, inject, mergeProps, normalizeProps, onBeforeUnmount, onMounted, openBlock, provide, ref, renderSlot, toDisplayString, unref, useSlots, useTemplateRef, watch, withDirectives } from "vue";
4
+ import { attachSubMenu, createSubMenu } from "@rio-m3e/core";
5
+ import "@rio-m3e/styles/base/focus-ring.css";
6
+ import "@rio-m3e/styles/base/reduced-motion.css";
7
+ import "@rio-m3e/styles/base/state-layer.css";
8
+ import "@rio-m3e/styles/base/anchored-position.css";
9
+ import "@rio-m3e/styles/menu.css";
10
+ // src/menu/SubMenu.vue
11
+ const _sfc_main = /*@__PURE__*/ defineComponent({
12
+ inheritAttrs: false,
13
+ __name: "SubMenu",
14
+ props: {
15
+ modelValue: {},
16
+ label: {},
17
+ disabled: { type: Boolean },
18
+ selection: {}
19
+ },
20
+ emits: ["update:modelValue"],
21
+ setup(__props, { emit: __emit }) {
22
+ const emit = __emit;
23
+ const slots = useSlots();
24
+ const parent = inject(menuKey, void 0);
25
+ const open = ref(false);
26
+ const sub = createSubMenu({
27
+ props: () => ({
28
+ label: __props.label,
29
+ disabled: __props.disabled,
30
+ selection: __props.selection,
31
+ selected: __props.modelValue
32
+ }),
33
+ content: () => ({
34
+ icon: !!slots.icon,
35
+ supportingText: !!slots["supporting-text"],
36
+ trailingText: !!slots["trailing-text"],
37
+ trailingIcon: !!slots["trailing-icon"]
38
+ }),
39
+ menu: () => parent,
40
+ open: () => open.value,
41
+ onChange: (selected) => emit("update:modelValue", selected),
42
+ onOpenChange: (next) => open.value = next
43
+ });
44
+ const { item } = sub;
45
+ provide(menuKey, menuContextOf(sub.menu));
46
+ const itemElement = useTemplateRef("itemElement");
47
+ const root = useTemplateRef("root");
48
+ let handle;
49
+ onMounted(() => {
50
+ handle = attachSubMenu(itemElement.value, root.value, { onOpenChange: (next) => open.value = next });
51
+ handle.sync(open.value);
52
+ });
53
+ watch(open, (next) => handle?.sync(next), { flush: "post" });
54
+ onBeforeUnmount(() => handle?.detach());
55
+ return (_ctx, _cache) => {
56
+ return openBlock(), createElementBlock(Fragment, null, [withDirectives((openBlock(), createElementBlock("button", mergeProps({
57
+ ref_key: "itemElement",
58
+ ref: itemElement
59
+ }, mergeProps(_ctx.$attrs, unref(item).parts.root()), { onClick: _cache[0] || (_cache[0] = (...args) => unref(item).handleClick && unref(item).handleClick(...args)) }), [
60
+ createElementVNode("span", normalizeProps(guardReactiveProps(unref(item).parts.touch())), null, 16),
61
+ unref(item).showsIcon() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 0 }, unref(item).parts.icon())), [renderSlot(_ctx.$slots, "icon")], 16)) : createCommentVNode("v-if", true),
62
+ createElementVNode("span", normalizeProps(guardReactiveProps(unref(item).parts.text())), [createElementVNode("span", normalizeProps(guardReactiveProps(unref(item).parts.label())), toDisplayString(__props.label), 17), unref(item).showsSupportingText() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 0 }, unref(item).parts.supportingText())), [renderSlot(_ctx.$slots, "supporting-text")], 16)) : createCommentVNode("v-if", true)], 16),
63
+ unref(item).showsTrailingText() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 1 }, unref(item).parts.trailingText())), [renderSlot(_ctx.$slots, "trailing-text")], 16)) : createCommentVNode("v-if", true),
64
+ unref(item).showsTrailingIcon() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 2 }, unref(item).parts.trailingIcon())), [renderSlot(_ctx.$slots, "trailing-icon")], 16)) : createCommentVNode("v-if", true)
65
+ ], 16)), [[unref(vRipple)]]), createElementVNode("div", mergeProps({
66
+ ref_key: "root",
67
+ ref: root
68
+ }, unref(sub).menu.parts.root()), [renderSlot(_ctx.$slots, "default")], 16)], 64);
69
+ };
70
+ }
71
+ });
72
+ export { _sfc_main as default };
@@ -0,0 +1,12 @@
1
+ // src/menu/context.ts
2
+ /** The parts of a core menu API that its items and submenus read */
3
+ const menuContextOf = (menu) => ({
4
+ selection: menu.selection,
5
+ isSelected: menu.isSelected,
6
+ choose: menu.choose,
7
+ close: menu.close,
8
+ variant: menu.variant,
9
+ instant: menu.instant
10
+ });
11
+ const menuKey = Symbol("RioMenu");
12
+ export { menuContextOf, menuKey };
@@ -19,11 +19,11 @@ declare const __VLS_base: import("vue").DefineComponent<SplitButtonProps, {
19
19
  leading: Readonly<import("vue").ShallowRef<HTMLButtonElement | null>>;
20
20
  trailing: Readonly<import("vue").ShallowRef<HTMLButtonElement | null>>;
21
21
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
22
- click: (event: MouseEvent) => any;
23
22
  "update:open": (open: boolean) => any;
23
+ click: (event: MouseEvent) => any;
24
24
  }, string, import("vue").PublicProps, Readonly<SplitButtonProps> & Readonly<{
25
- onClick?: ((event: MouseEvent) => any) | undefined;
26
25
  "onUpdate:open"?: ((open: boolean) => any) | undefined;
26
+ onClick?: ((event: MouseEvent) => any) | undefined;
27
27
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
28
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
29
29
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,40 @@
1
+ import { TooltipProps } from "@rio-m3e/core";
2
+ import "@rio-m3e/styles/base/reduced-motion.css";
3
+ import "@rio-m3e/styles/base/anchored-position.css";
4
+ import "@rio-m3e/styles/tooltip.css";
5
+ interface Props extends Omit<TooltipProps, 'open'> {
6
+ /** The tooltip's text. The `content` slot takes richer content instead. */
7
+ text?: string;
8
+ /** A subhead above the text (rich only) */
9
+ subhead?: string;
10
+ }
11
+ type __VLS_Props = Props;
12
+ type __VLS_Slots = {
13
+ /** The element the tooltip is for, such as a button. One element. */
14
+ default?: () => unknown;
15
+ /** The tooltip's text, in place of the `text` prop */
16
+ content?: () => unknown;
17
+ /** Up to two text buttons (rich only). They make the tooltip a non-modal dialog. */
18
+ actions?: () => unknown;
19
+ };
20
+ type __VLS_ModelProps = {
21
+ /**
22
+ * Whether the tooltip is shown, with `v-model:open`. Without it the tooltip keeps the state
23
+ * itself; with it, the app can open a persistent tooltip as the page loads.
24
+ */
25
+ 'open'?: boolean;
26
+ };
27
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
28
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
29
+ "update:open": (value: boolean) => any;
30
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
31
+ "onUpdate:open"?: ((value: boolean) => any) | undefined;
32
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
33
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
34
+ declare const _default: typeof __VLS_export;
35
+ type __VLS_WithSlots<T, S> = T & {
36
+ new (): {
37
+ $slots: S;
38
+ };
39
+ };
40
+ export { _default as default };
@@ -0,0 +1,82 @@
1
+ import { createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, guardReactiveProps, mergeModels, mergeProps, normalizeProps, onBeforeUnmount, onMounted, onUpdated, openBlock, renderSlot, toDisplayString, unref, useId, useModel, useSlots, useTemplateRef, watch } from "vue";
2
+ import { attachTooltip, createTooltip } from "@rio-m3e/core";
3
+ import "@rio-m3e/styles/base/reduced-motion.css";
4
+ import "@rio-m3e/styles/base/anchored-position.css";
5
+ import "@rio-m3e/styles/tooltip.css";
6
+ // src/tooltip/Tooltip.vue
7
+ const _sfc_main = /*@__PURE__*/ defineComponent({
8
+ __name: "Tooltip",
9
+ props: /*@__PURE__*/ mergeModels({
10
+ text: {},
11
+ subhead: {},
12
+ variant: {},
13
+ persistent: { type: Boolean },
14
+ side: {},
15
+ align: {},
16
+ offset: {}
17
+ }, {
18
+ "open": {
19
+ type: Boolean,
20
+ default: false
21
+ },
22
+ "openModifiers": {}
23
+ }),
24
+ emits: ["update:open"],
25
+ setup(__props) {
26
+ /**
27
+ * Whether the tooltip is shown, with `v-model:open`. Without it the tooltip keeps the state
28
+ * itself; with it, the app can open a persistent tooltip as the page loads.
29
+ */
30
+ const open = useModel(__props, "open");
31
+ const slots = useSlots();
32
+ const id = useId();
33
+ const tooltip = createTooltip({
34
+ props: () => ({
35
+ variant: __props.variant,
36
+ persistent: __props.persistent,
37
+ open: open.value,
38
+ side: __props.side,
39
+ align: __props.align,
40
+ offset: __props.offset
41
+ }),
42
+ content: () => ({
43
+ subhead: !!__props.subhead,
44
+ actions: !!slots.actions
45
+ }),
46
+ ids: {
47
+ root: `${id}-tooltip`,
48
+ subhead: `${id}-subhead`,
49
+ supportingText: `${id}-text`
50
+ }
51
+ });
52
+ const trigger = useTemplateRef("trigger");
53
+ const root = useTemplateRef("root");
54
+ let handle;
55
+ onMounted(() => {
56
+ handle = attachTooltip(trigger.value, root.value, {
57
+ placement: tooltip.placement,
58
+ persistent: tooltip.persistent,
59
+ interactive: tooltip.interactive,
60
+ onOpenChange: (next) => open.value = next
61
+ });
62
+ handle.sync(open.value);
63
+ });
64
+ watch(open, (next) => handle?.sync(next), { flush: "post" });
65
+ onUpdated(() => handle?.update());
66
+ onBeforeUnmount(() => handle?.detach());
67
+ return (_ctx, _cache) => {
68
+ return openBlock(), createElementBlock("span", mergeProps({
69
+ ref_key: "trigger",
70
+ ref: trigger
71
+ }, unref(tooltip).parts.trigger()), [renderSlot(_ctx.$slots, "default"), createElementVNode("span", mergeProps({
72
+ ref_key: "root",
73
+ ref: root
74
+ }, unref(tooltip).parts.root()), [
75
+ unref(tooltip).showsSubhead() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 0 }, unref(tooltip).parts.subhead())), toDisplayString(__props.subhead), 17)) : createCommentVNode("v-if", true),
76
+ createElementVNode("span", normalizeProps(guardReactiveProps(unref(tooltip).parts.supportingText())), [renderSlot(_ctx.$slots, "content", {}, () => [createTextVNode(toDisplayString(__props.text), 1)])], 16),
77
+ unref(tooltip).showsActions() ? (openBlock(), createElementBlock("span", normalizeProps(mergeProps({ key: 1 }, unref(tooltip).parts.actions())), [renderSlot(_ctx.$slots, "actions")], 16)) : createCommentVNode("v-if", true)
78
+ ], 16)], 16);
79
+ };
80
+ }
81
+ });
82
+ export { _sfc_main as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rio-m3e/vue",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Vue components for Rio, a Material 3 Expressive implementation",
5
5
  "license": "Apache-2.0",
6
6
  "author": "LegenLee",
@@ -27,13 +27,14 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@rio-m3e/core": "^0.2.0",
31
- "@rio-m3e/styles": "^0.2.0"
30
+ "@rio-m3e/core": "^0.3.0",
31
+ "@rio-m3e/styles": "^0.3.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@fontsource/roboto": "^5.3.0",
35
35
  "@mdi/js": "^7.4.47",
36
- "@rio-m3e/tokens": "^0.2.0",
36
+ "@rio-m3e/testing": "^0.0.0",
37
+ "@rio-m3e/tokens": "^0.3.0",
37
38
  "tsdown": "0.23.7",
38
39
  "typescript": "~6.0.3",
39
40
  "unplugin-vue": "^8.0.1",