ropav 0.10.0 → 0.11.1

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 (35) hide show
  1. package/dist/components/autocomplete/autocomplete-filter.d.ts +1 -1
  2. package/dist/components/avatar/avatar-root.js +4 -1
  3. package/dist/components/avatar-group/avatar-group-overflow.d.ts +21 -0
  4. package/dist/components/avatar-group/avatar-group-overflow.js +42 -0
  5. package/dist/components/avatar-group/avatar-group-root.d.ts +21 -0
  6. package/dist/components/avatar-group/avatar-group-root.js +35 -0
  7. package/dist/components/avatar-group/avatar-group.context.d.ts +12 -0
  8. package/dist/components/avatar-group/avatar-group.context.js +13 -0
  9. package/dist/components/avatar-group/avatar-group.types.d.ts +26 -0
  10. package/dist/components/avatar-group/index.d.ts +8 -0
  11. package/dist/components/avatar-group/index.js +5 -0
  12. package/dist/components/button/button-root.js +1 -1
  13. package/dist/components/dropdown/dropdown-trigger.js +25 -4
  14. package/dist/components/dropdown/dropdown.types.d.ts +2 -0
  15. package/dist/components/index.d.ts +1 -0
  16. package/dist/components/list-box-item/list-box-item-root.js +4 -1
  17. package/dist/components/overlay/overlay-arrow.js +1 -1
  18. package/dist/components/sidebar/sidebar.types.d.ts +1 -1
  19. package/dist/components/skeleton/skeleton-root.js +1 -1
  20. package/dist/components/skeleton/skeleton.types.d.ts +1 -1
  21. package/dist/components/textarea/textarea-root.js +20 -0
  22. package/dist/components/textarea/textarea.types.d.ts +21 -0
  23. package/dist/components/tooltip/tooltip-root.js +2 -2
  24. package/dist/components/tooltip/tooltip.types.d.ts +2 -2
  25. package/dist/composables/press-responder.d.ts +6 -0
  26. package/dist/composables/use-css-variable.d.ts +1 -1
  27. package/dist/composables/use-css-variable.js +1 -1
  28. package/dist/composables/use-menu-trigger.js +1 -0
  29. package/dist/composables/use-textarea-autosize.d.ts +55 -0
  30. package/dist/composables/use-textarea-autosize.js +189 -0
  31. package/dist/index.js +5 -1
  32. package/dist/ropav.min.css +1 -1
  33. package/dist/styles-compat-0.10.css +3 -0
  34. package/dist/version.js +1 -1
  35. package/package.json +10 -2
@@ -1,5 +1,5 @@
1
1
  import type { AutocompleteFilterProps, AutocompleteFilterSlotProps } from "./autocomplete.types.js";
2
- declare const __VLS_export: <T>(__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<{
2
+ declare const __VLS_export: <T = any>(__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<{
3
3
  props: import('vue').PublicProps & __VLS_PrettifyLocal<AutocompleteFilterProps<T> & {
4
4
  onInputChange?: ((value: string) => any) | undefined;
5
5
  "onUpdate:inputValue"?: ((value: string) => any) | undefined;
@@ -1,4 +1,5 @@
1
1
  import { provideAvatarContext } from "./avatar.context.js";
2
+ import { useAvatarGroupContext } from "../avatar-group/avatar-group.context.js";
2
3
  import { computed, createSlot, defineVaporComponent, renderEffect, setClass, setInsertionState, shallowRef, template } from "vue";
3
4
  import { avatarVariants } from "@ropav/styles";
4
5
  //#region src/components/avatar/avatar-root.vue?vue&type=script&setup=true&vapor=true&lang.ts
@@ -13,9 +14,11 @@ var avatar_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__PU
13
14
  },
14
15
  setup(__props) {
15
16
  const props = __props;
17
+ const group = useAvatarGroupContext();
18
+ const resolvedSize = computed(() => props.size ?? group?.size.value);
16
19
  const slots = computed(() => avatarVariants({
17
20
  color: props.color,
18
- size: props.size,
21
+ size: resolvedSize.value,
19
22
  variant: props.variant
20
23
  }));
21
24
  const imageStatus = shallowRef("idle");
@@ -0,0 +1,21 @@
1
+ import type { AvatarGroupOverflowProps } from "./avatar-group.types.js";
2
+ declare const __VLS_export: (__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<{
3
+ props: import('vue').PublicProps & __VLS_PrettifyLocal<AvatarGroupOverflowProps> & (typeof globalThis extends {
4
+ __VLS_PROPS_FALLBACK: infer P;
5
+ } ? P : {});
6
+ expose: (exposed: {}) => void;
7
+ attrs: any;
8
+ slots: {
9
+ default?: () => unknown;
10
+ };
11
+ emit: {};
12
+ }>) => import('vue').VNode & {
13
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
14
+ };
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
18
+ [K in keyof T]: T[K];
19
+ } : {
20
+ [K in keyof T as K]: T[K];
21
+ }) & {};
@@ -0,0 +1,42 @@
1
+ import { composeSlotClassName } from "../../utils/compose.js";
2
+ import avatar_fallback_default from "../avatar/avatar-fallback.js";
3
+ import { useAvatarGroupContext } from "./avatar-group.context.js";
4
+ import avatar_root_default from "../avatar/avatar-root.js";
5
+ import { computed, createComponent, createIf, createSlot, defineVaporComponent, extend, renderEffect, setText, template, toDisplayString, unref, useSlots } from "vue";
6
+ //#region src/components/avatar-group/avatar-group-overflow.vue?vue&type=script&setup=true&vapor=true&lang.ts
7
+ var t0 = template(" ");
8
+ var avatar_group_overflow_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__PURE__*/ defineVaporComponent({
9
+ __name: "avatar-group-overflow",
10
+ props: {
11
+ class: {},
12
+ count: {}
13
+ },
14
+ setup(__props) {
15
+ const props = __props;
16
+ const callerSlots = useSlots();
17
+ /**
18
+ * Whether the caller wrote a slot at all, read off its presence and never by running it. A
19
+ * default written as `<slot>` fallback content drops the slots of anything nested inside it on
20
+ * the first render from a VDOM host, so both paths are kept apart instead.
21
+ */
22
+ const hasSlot = computed(() => Boolean(callerSlots["default"]));
23
+ const context = useAvatarGroupContext();
24
+ const overflowClass = computed(() => composeSlotClassName(context?.slots.value.overflow, props.class));
25
+ return createComponent(unref(avatar_root_default), {
26
+ class: () => overflowClass.value,
27
+ "data-slot": "avatar-group-overflow"
28
+ }, () => {
29
+ return createComponent(unref(avatar_fallback_default), null, extend(() => {
30
+ return createIf(() => hasSlot.value, () => {
31
+ return createSlot("default", null, null, 4);
32
+ }, () => createIf(() => props.count !== void 0, () => {
33
+ const n5 = t0();
34
+ renderEffect(() => setText(n5, "+" + toDisplayString(props.count)));
35
+ return n5;
36
+ }, null, 129), 389);
37
+ }, { _: 1 }));
38
+ }, true);
39
+ }
40
+ });
41
+ //#endregion
42
+ export { avatar_group_overflow_vue_vue_type_script_setup_true_vapor_true_lang_default as default };
@@ -0,0 +1,21 @@
1
+ import type { AvatarGroupRootProps } from "./avatar-group.types.js";
2
+ declare const __VLS_export: (__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<{
3
+ props: import('vue').PublicProps & __VLS_PrettifyLocal<AvatarGroupRootProps> & (typeof globalThis extends {
4
+ __VLS_PROPS_FALLBACK: infer P;
5
+ } ? P : {});
6
+ expose: (exposed: {}) => void;
7
+ attrs: any;
8
+ slots: {
9
+ default?: () => unknown;
10
+ };
11
+ emit: {};
12
+ }>) => import('vue').VNode & {
13
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
14
+ };
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
17
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
18
+ [K in keyof T]: T[K];
19
+ } : {
20
+ [K in keyof T as K]: T[K];
21
+ }) & {};
@@ -0,0 +1,35 @@
1
+ import { provideAvatarGroupContext } from "./avatar-group.context.js";
2
+ import { computed, createSlot, defineVaporComponent, renderEffect, setClass, setInsertionState, template } from "vue";
3
+ import { avatarGroupVariants } from "@ropav/styles";
4
+ //#region src/components/avatar-group/avatar-group-root.vue?vue&type=script&setup=true&vapor=true&lang.ts
5
+ var t0 = template("<div data-slot=avatar-group>", 1);
6
+ var avatar_group_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__PURE__*/ defineVaporComponent({
7
+ __name: "avatar-group-root",
8
+ props: {
9
+ class: {},
10
+ front: {},
11
+ orientation: {},
12
+ overlap: {},
13
+ size: {}
14
+ },
15
+ setup(__props) {
16
+ const props = __props;
17
+ const slots = computed(() => avatarGroupVariants({
18
+ front: props.front,
19
+ orientation: props.orientation,
20
+ overlap: props.overlap,
21
+ size: props.size
22
+ }));
23
+ provideAvatarGroupContext({
24
+ size: computed(() => props.size),
25
+ slots
26
+ });
27
+ const n1 = t0();
28
+ renderEffect(() => setClass(n1, slots.value.base({ class: props.class })));
29
+ setInsertionState(n1);
30
+ createSlot();
31
+ return n1;
32
+ }
33
+ });
34
+ //#endregion
35
+ export { avatar_group_root_vue_vue_type_script_setup_true_vapor_true_lang_default as default };
@@ -0,0 +1,12 @@
1
+ import type { avatarGroupVariants, AvatarVariants } from "@ropav/styles";
2
+ import type { ComputedRef } from "vue";
3
+ export interface AvatarGroupContext {
4
+ slots: ComputedRef<ReturnType<typeof avatarGroupVariants>>;
5
+ /** Size for every avatar in the group, which each avatar may still override. */
6
+ size: ComputedRef<AvatarVariants["size"]>;
7
+ }
8
+ /**
9
+ * Loose on purpose: an Avatar reads this context but is perfectly usable on its own, so the
10
+ * absence of a group is a normal state rather than an error.
11
+ */
12
+ export declare const useAvatarGroupContext: () => AvatarGroupContext | null, provideAvatarGroupContext: (value: AvatarGroupContext | null) => AvatarGroupContext | null;
@@ -0,0 +1,13 @@
1
+ import { createContext } from "../../utils/create-context.js";
2
+ //#region src/components/avatar-group/avatar-group.context.ts
3
+ /**
4
+ * Loose on purpose: an Avatar reads this context but is perfectly usable on its own, so the
5
+ * absence of a group is a normal state rather than an error.
6
+ */
7
+ var [useAvatarGroupContext, provideAvatarGroupContext] = createContext({
8
+ defaultValue: null,
9
+ name: "AvatarGroupContext",
10
+ strict: false
11
+ });
12
+ //#endregion
13
+ export { provideAvatarGroupContext, useAvatarGroupContext };
@@ -0,0 +1,26 @@
1
+ import type { AvatarGroupVariants, AvatarVariants } from "@ropav/styles";
2
+ export interface AvatarGroupRootProps {
3
+ class?: string;
4
+ /**
5
+ * Which avatar is in front. `"last"` is the order the document paints in already, so it costs
6
+ * no stacking rule; `"first"` reverses it. @default "last"
7
+ */
8
+ front?: AvatarGroupVariants["front"];
9
+ /** Axis the avatars are laid out along. @default "horizontal" */
10
+ orientation?: AvatarGroupVariants["orientation"];
11
+ /**
12
+ * How far each avatar tucks under its neighbour, as a share of one avatar. `"none"` spaces them
13
+ * out instead, and drops the ring with it. @default "md"
14
+ */
15
+ overlap?: AvatarGroupVariants["overlap"];
16
+ /** Size for every avatar in the group. Each avatar can still set its own. @default "md" */
17
+ size?: AvatarVariants["size"];
18
+ }
19
+ export interface AvatarGroupOverflowProps {
20
+ class?: string;
21
+ /**
22
+ * How many avatars are not shown, rendered as `+count`. Write the slot instead where the count
23
+ * needs words around it.
24
+ */
25
+ count?: number;
26
+ }
@@ -0,0 +1,8 @@
1
+ import AvatarGroupOverflow from "./avatar-group-overflow.js";
2
+ import AvatarGroupRoot from "./avatar-group-root.js";
3
+ export { AvatarGroupRoot as AvatarGroup, AvatarGroupOverflow };
4
+ export type { AvatarGroupRootProps as AvatarGroupProps, AvatarGroupOverflowProps, } from "./avatar-group.types.js";
5
+ export { useAvatarGroupContext } from "./avatar-group.context.js";
6
+ export type { AvatarGroupContext } from "./avatar-group.context.js";
7
+ export { avatarGroupVariants } from "@ropav/styles";
8
+ export type { AvatarGroupVariants } from "@ropav/styles";
@@ -0,0 +1,5 @@
1
+ import { useAvatarGroupContext } from "./avatar-group.context.js";
2
+ import avatar_group_overflow_default from "./avatar-group-overflow.js";
3
+ import avatar_group_root_default from "./avatar-group-root.js";
4
+ import { avatarGroupVariants } from "@ropav/styles";
5
+ export { avatar_group_root_default as AvatarGroup, avatar_group_overflow_default as AvatarGroupOverflow, avatarGroupVariants, useAvatarGroupContext };
@@ -48,7 +48,7 @@ var button_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__PU
48
48
  focusResponder?.registerElement(next);
49
49
  };
50
50
  const resolvedFullWidth = computed(() => props.fullWidth ?? group?.fullWidth.value);
51
- const resolvedIsDisabled = computed(() => props.isDisabled ?? group?.isDisabled.value ?? fieldset?.isDisabled.value);
51
+ const resolvedIsDisabled = computed(() => props.isDisabled ?? responder?.isDisabled?.value ?? group?.isDisabled.value ?? fieldset?.isDisabled.value);
52
52
  const resolvedSize = computed(() => props.size ?? group?.size.value);
53
53
  const resolvedVariant = computed(() => props.variant ?? group?.variant.value);
54
54
  const styles = computed(() => buttonVariants({
@@ -1,12 +1,17 @@
1
1
  import { dataAttr } from "../../utils/assertion.js";
2
+ import { useInteractionStates } from "../../composables/use-interaction-states.js";
2
3
  import { composePressResponder, usePressResponder } from "../../composables/press-responder.js";
3
- import { createSlot, defineVaporComponent, on, renderEffect, setDynamicProps, setInsertionState, setTemplateRefBinding, template, unref } from "vue";
4
+ import { computed, createSlot, defineVaporComponent, on, renderEffect, setDynamicProps, setInsertionState, setTemplateRefBinding, template, unref } from "vue";
4
5
  //#region src/components/dropdown/dropdown-trigger.vue?vue&type=script&setup=true&vapor=true&lang.ts
5
6
  var t0 = template("<button>", 1);
6
7
  var dropdown_trigger_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__PURE__*/ defineVaporComponent({
7
8
  __name: "dropdown-trigger",
8
9
  props: {
9
10
  class: {},
11
+ isDisabled: {
12
+ type: Boolean,
13
+ default: void 0
14
+ },
10
15
  type: { default: "button" }
11
16
  },
12
17
  setup(__props) {
@@ -15,23 +20,39 @@ var dropdown_trigger_vue_vue_type_script_setup_true_vapor_true_lang_default = /*
15
20
  const setElement = (element) => {
16
21
  responder?.registerElement(element ?? null);
17
22
  };
18
- const press = composePressResponder(responder);
23
+ const resolvedIsDisabled = computed(() => props.isDisabled ?? responder?.isDisabled?.value);
24
+ const { isFocusVisible, isFocused, isHovered, isPressed, onBlur, onFocus, onPointerdown, onPointerenter, onPointerleave } = useInteractionStates({ isDisabled: () => resolvedIsDisabled.value });
25
+ const tabindex = computed(() => resolvedIsDisabled.value ? void 0 : 0);
26
+ const press = composePressResponder(responder, {
27
+ onPointerdown,
28
+ onPointerenter,
29
+ onPointerleave
30
+ });
19
31
  const n1 = t0();
20
32
  renderEffect(() => {
21
33
  const _props = props;
34
+ const _dataAttr = unref(dataAttr);
35
+ const _resolvedIsDisabled = resolvedIsDisabled.value;
22
36
  const _responder = unref(responder);
23
37
  setDynamicProps(n1, [{
24
38
  class: ["rp-dropdown__trigger", _props.class],
25
- "data-pressed": unref(dataAttr)(_responder?.isPressed.value),
39
+ "data-disabled": _dataAttr(_resolvedIsDisabled),
40
+ "data-focus-visible": _dataAttr(unref(isFocusVisible)),
41
+ "data-focused": _dataAttr(unref(isFocused)),
42
+ "data-hovered": _dataAttr(unref(isHovered)),
43
+ "data-pressed": _dataAttr(unref(isPressed) || _responder?.isPressed.value),
26
44
  "data-slot": "dropdown-trigger",
27
- tabindex: "0",
45
+ disabled: _resolvedIsDisabled || void 0,
46
+ tabindex: tabindex.value,
28
47
  type: _props.type
29
48
  }, _responder?.attrs.value]);
30
49
  });
31
50
  setInsertionState(n1);
32
51
  createSlot();
52
+ on(n1, "blur", (e) => unref(onBlur)(e));
33
53
  on(n1, "click", (e) => unref(press).onClick(e));
34
54
  on(n1, "dragstart", (e) => unref(press).onDragstart(e));
55
+ on(n1, "focus", (e) => unref(onFocus)(e));
35
56
  on(n1, "keydown", (e) => unref(press).onKeydown(e));
36
57
  on(n1, "mousedown", (e) => unref(press).onMousedown(e));
37
58
  on(n1, "pointerdown", (e) => unref(press).onPointerdown(e));
@@ -15,6 +15,8 @@ export interface DropdownRootEmits {
15
15
  }
16
16
  export interface DropdownTriggerProps {
17
17
  class?: string;
18
+ /** Disables the trigger. Falls back to the state the dropdown root supplies. */
19
+ isDisabled?: boolean;
18
20
  /** Native button type. @default "button" */
19
21
  type?: "button" | "reset" | "submit";
20
22
  }
@@ -3,6 +3,7 @@ export * from "./alert/index.js";
3
3
  export * from "./alert-dialog/index.js";
4
4
  export * from "./autocomplete/index.js";
5
5
  export * from "./avatar/index.js";
6
+ export * from "./avatar-group/index.js";
6
7
  export * from "./badge/index.js";
7
8
  export * from "./breadcrumbs/index.js";
8
9
  export * from "./button/index.js";
@@ -54,7 +54,10 @@ var list_box_item_root_vue_vue_type_script_setup_true_vapor_true_lang_default =
54
54
  const isSelected = computed(() => selection.isSelected(itemKey.value));
55
55
  const isDisabled = computed(() => selection.isDisabled(itemKey.value));
56
56
  const selectionMode = computed(() => selection.selectionMode.value);
57
- const fieldIds = useFieldIds({ slots: ["description"] });
57
+ const fieldIds = useFieldIds({
58
+ labelElementType: "span",
59
+ slots: ["description"]
60
+ });
58
61
  provideFieldIdsContext(fieldIds.context);
59
62
  provideListBoxItemContext({
60
63
  isSelected,
@@ -1,7 +1,7 @@
1
1
  import { useOverlayArrowContext } from "./overlay.context.js";
2
2
  import { child, computed, createSlot, defineVaporComponent, renderEffect, setAttr, setClass, setInsertionState, setStyle, setTemplateRefBinding, shallowRef, template, watch } from "vue";
3
3
  //#region src/components/overlay/overlay-arrow.vue?vue&type=script&setup=true&vapor=true&lang.ts
4
- var t0 = template("<div><!><svg aria-hidden=true focusable=false height=0 style=\"position: absolute\" width=0><filter id=ropav-overlay-edge color-interpolation-filters=sRGB height=200% width=200% x=-50% y=-50%><feFlood result=line style=\"flood-color: var(--overlay-edge-line, transparent)\"></feFlood><feComposite in=line in2=SourceAlpha operator=out result=outside></feComposite><feGaussianBlur in=outside result=soft stdDeviation=0.5></feGaussianBlur><feComposite in=soft in2=SourceAlpha operator=in result=glow></feComposite><feMerge><feMergeNode in=SourceGraphic></feMergeNode><feMergeNode in=glow>", 1);
4
+ var t0 = template("<div><!><svg aria-hidden=true focusable=false height=0 style=\"position: absolute\" width=0><filter id=ropav-overlay-edge color-interpolation-filters=sRGB height=200% width=200% x=-50% y=-50%><feFlood result=line style=\"flood-color: var(--rp-overlay-edge-line, transparent)\"></feFlood><feComposite in=line in2=SourceAlpha operator=out result=outside></feComposite><feGaussianBlur in=outside result=soft stdDeviation=0.5></feGaussianBlur><feComposite in=soft in2=SourceAlpha operator=in result=glow></feComposite><feMerge><feMergeNode in=SourceGraphic></feMergeNode><feMergeNode in=glow>", 1);
5
5
  var SKIRT = 2;
6
6
  /** Half the mouth's width: the shape's mouth spans the middle 10 of its 12 unit box. */
7
7
  var HALF_MOUTH = 5;
@@ -231,7 +231,7 @@ export interface SidebarItemTooltipProps {
231
231
  /**
232
232
  * How long the pointer has to rest on the item before the tooltip opens.
233
233
  *
234
- * Left to the theme's `--tooltip-delay` by default, the same as every other tooltip. A rail is a
234
+ * Left to the theme's `--rp-tooltip-delay` by default, the same as every other tooltip. A rail is a
235
235
  * good reason to want this shorter — the label is the only way to read the item, not a hint
236
236
  * beside one — but that is a decision about the whole product's tooltips, not about this part.
237
237
  */
@@ -11,7 +11,7 @@ var skeleton_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__
11
11
  },
12
12
  setup(__props) {
13
13
  const props = __props;
14
- const resolvedAnimationType = useCssVariable("--skeleton-animation", { override: () => props.animationType });
14
+ const resolvedAnimationType = useCssVariable("--rp-skeleton-animation", { override: () => props.animationType });
15
15
  const styles = computed(() => skeletonVariants({ animationType: resolvedAnimationType.value }).base({ class: props.class }));
16
16
  const n1 = t0();
17
17
  renderEffect(() => setClass(n1, styles.value));
@@ -1,6 +1,6 @@
1
1
  import type { SkeletonVariants } from "@ropav/styles";
2
2
  export interface SkeletonRootProps {
3
3
  class?: string;
4
- /** Animation type. Falls back to the theme's `--skeleton-animation` value. */
4
+ /** Animation type. Falls back to the theme's `--rp-skeleton-animation` value. */
5
5
  animationType?: SkeletonVariants["animationType"];
6
6
  }
@@ -3,6 +3,7 @@ import { useInteractionStates } from "../../composables/use-interaction-states.j
3
3
  import { setFormValue } from "../../utils/form-value.js";
4
4
  import { useTextFieldControlContext } from "../../composables/use-text-field.js";
5
5
  import { useTextFieldContext } from "../textfield/textfield.context.js";
6
+ import { useTextareaAutosize } from "../../composables/use-textarea-autosize.js";
6
7
  import { computed, createTemplateRefSetter, defineVaporComponent, on, renderEffect, setDynamicProps, shallowRef, template, unref, watch } from "vue";
7
8
  import { textAreaVariants } from "@ropav/styles";
8
9
  //#region src/components/textarea/textarea-root.vue?vue&type=script&setup=true&vapor=true&lang.ts
@@ -18,6 +19,13 @@ var textarea_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__
18
19
  type: Boolean,
19
20
  default: void 0
20
21
  },
22
+ autosize: {
23
+ type: Boolean,
24
+ default: void 0
25
+ },
26
+ minRows: { default: void 0 },
27
+ maxRows: { default: void 0 },
28
+ resize: { default: void 0 },
21
29
  placeholder: {}
22
30
  },
23
31
  emits: ["change", "update:value"],
@@ -33,9 +41,11 @@ var textarea_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__
33
41
  };
34
42
  const resolvedVariant = computed(() => props.variant ?? textField?.variant.value);
35
43
  const resolvedSize = computed(() => props.size ?? textField?.size.value);
44
+ const resolvedResize = computed(() => props.autosize ? "none" : props.resize);
36
45
  const styles = computed(() => textAreaVariants({
37
46
  class: props.class,
38
47
  fullWidth: props.fullWidth,
48
+ resize: resolvedResize.value,
39
49
  size: resolvedSize.value,
40
50
  variant: resolvedVariant.value
41
51
  }));
@@ -43,15 +53,24 @@ var textarea_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__
43
53
  const merged = { ...control?.attrs.value };
44
54
  if (props.placeholder !== void 0) merged["placeholder"] = props.placeholder;
45
55
  if (props.value !== void 0) merged["value"] = props.value;
56
+ if (props.autosize && props.minRows !== void 0) merged["rows"] = props.minRows;
46
57
  return merged;
47
58
  });
48
59
  const interaction = useInteractionStates({ isDisabled: () => control?.isDisabled.value });
49
60
  const inputCount = shallowRef(0);
61
+ const { sync: syncAutosize } = useTextareaAutosize({
62
+ content: () => control?.attrs.value["value"],
63
+ element,
64
+ enabled: () => props.autosize,
65
+ maxRows: () => props.maxRows,
66
+ minRows: () => props.minRows
67
+ });
50
68
  const onInput = (event) => {
51
69
  control?.handlers.onInput(event);
52
70
  const next = event.currentTarget.value;
53
71
  emit("change", next);
54
72
  emit("update:value", next);
73
+ syncAutosize({ fromInput: true });
55
74
  if (props.value !== void 0) inputCount.value++;
56
75
  };
57
76
  /**
@@ -66,6 +85,7 @@ var textarea_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__
66
85
  ], ([el, pinned]) => {
67
86
  if (pinned === void 0) return;
68
87
  setFormValue(el, pinned);
88
+ syncAutosize();
69
89
  }, {
70
90
  flush: "post",
71
91
  immediate: true
@@ -16,6 +16,27 @@ export interface TextAreaRootProps {
16
16
  size?: TextAreaVariants["size"];
17
17
  /** Whether the control stretches to fill its container. */
18
18
  fullWidth?: boolean;
19
+ /**
20
+ * Whether the control grows with its content. `minRows` and `maxRows` only apply when this
21
+ * is set. Native resize is forced off while it is, so the drag handle cannot fight the
22
+ * measured height. @default false
23
+ */
24
+ autosize?: boolean;
25
+ /**
26
+ * Minimum visible rows while `autosize` is set. Ignored otherwise. Written through to the
27
+ * native `rows` attribute so the first paint is already that tall.
28
+ */
29
+ minRows?: number;
30
+ /**
31
+ * Maximum visible rows while `autosize` is set. Ignored otherwise. Absent, the control grows
32
+ * without a cap.
33
+ */
34
+ maxRows?: number;
35
+ /**
36
+ * Whether the pointer can drag the edge. `none` by default; `vertical` or `both` opt in.
37
+ * Ignored while `autosize` is set. @default "none"
38
+ */
39
+ resize?: TextAreaVariants["resize"];
19
40
  /**
20
41
  * Placeholder shown while the control is empty. Declared so it can also be set here rather
21
42
  * than only on the field; every other native attribute arrives by attribute fallthrough.
@@ -39,8 +39,8 @@ var tooltip_root_vue_vue_type_script_setup_true_vapor_true_lang_default = /*@__P
39
39
  * changes one declaration instead of every call site. A prop still wins, and the built-in defaults
40
40
  * are the floor when the property is not declared at all.
41
41
  */
42
- const cssDelay = useCssVariable("--tooltip-delay");
43
- const cssCloseDelay = useCssVariable("--tooltip-close-delay");
42
+ const cssDelay = useCssVariable("--rp-tooltip-delay");
43
+ const cssCloseDelay = useCssVariable("--rp-tooltip-close-delay");
44
44
  const state = useTooltipTriggerState({
45
45
  closeDelay: () => props.closeDelay ?? parseCssTime(cssCloseDelay.value),
46
46
  defaultOpen: props.defaultOpen,
@@ -6,13 +6,13 @@ export interface TooltipRootProps {
6
6
  /**
7
7
  * How long the pointer has to rest on the trigger before the tooltip opens.
8
8
  *
9
- * @default the `--tooltip-delay` custom property, or 1500
9
+ * @default the `--rp-tooltip-delay` custom property, or 1500
10
10
  */
11
11
  delay?: number;
12
12
  /**
13
13
  * How long the tooltip stays after the pointer leaves.
14
14
  *
15
- * @default the `--tooltip-close-delay` custom property, or 500
15
+ * @default the `--rp-tooltip-close-delay` custom property, or 500
16
16
  */
17
17
  closeDelay?: number;
18
18
  /** Opens on hover and on keyboard focus, or on focus alone. @default "hover" */
@@ -9,6 +9,12 @@ export interface PressResponder {
9
9
  attrs: ComputedRef<Record<string, unknown>>;
10
10
  /** Listeners the pressable chains ahead of its own, through {@link composePressResponder}. */
11
11
  handlers: ComputedRef<UsePressHandlers>;
12
+ /**
13
+ * Whether the pressable should be disabled regardless of its own state. Holds `undefined` when
14
+ * nothing above has an opinion, which is what lets a pressable resolving this against its own
15
+ * group or fieldset tell "enabled" apart from "unstated".
16
+ */
17
+ isDisabled?: ComputedRef<boolean | undefined>;
12
18
  /** Whether the pressable should look pressed regardless of its own state. */
13
19
  isPressed: ComputedRef<boolean>;
14
20
  /** Reports the pressable's element, which is what the responder acts on and positions against. */
@@ -14,7 +14,7 @@ export interface UseCssVariableOptions {
14
14
  *
15
15
  * @example
16
16
  * ```ts
17
- * const delay = computed(() => parseCssTime(useCssVariable("--tooltip-delay").value));
17
+ * const delay = computed(() => parseCssTime(useCssVariable("--rp-tooltip-delay").value));
18
18
  * ```
19
19
  */
20
20
  export declare const useCssVariable: (name: MaybeRefOrGetter<string>, options?: UseCssVariableOptions) => ComputedRef<string | undefined>;
@@ -16,7 +16,7 @@ var cache = /* @__PURE__ */ new Map();
16
16
  *
17
17
  * @example
18
18
  * ```ts
19
- * const delay = computed(() => parseCssTime(useCssVariable("--tooltip-delay").value));
19
+ * const delay = computed(() => parseCssTime(useCssVariable("--rp-tooltip-delay").value));
20
20
  * ```
21
21
  */
22
22
  var useCssVariable = (name, options = {}) => {
@@ -102,6 +102,7 @@ var useMenuTrigger = (options, state) => {
102
102
  }
103
103
  };
104
104
  }),
105
+ isDisabled: computed(() => toValue(options.isDisabled)),
105
106
  isPressed: press.isPressed,
106
107
  registerElement: (next) => {
107
108
  element.value = next;
@@ -0,0 +1,55 @@
1
+ import type { MaybeRefOrGetter } from "vue";
2
+ export interface UseTextareaAutosizeOptions {
3
+ element: MaybeRefOrGetter<HTMLTextAreaElement | null | undefined>;
4
+ /** When false, inline height and overflow are cleared and the native `rows` height is used. */
5
+ enabled: MaybeRefOrGetter<boolean | undefined>;
6
+ /** Floor, in rows. Ignored when `enabled` is false. */
7
+ minRows: MaybeRefOrGetter<number | undefined>;
8
+ /** Ceiling, in rows. Absent, the control grows without a cap. Ignored when `enabled` is false. */
9
+ maxRows: MaybeRefOrGetter<number | undefined>;
10
+ /**
11
+ * Text held somewhere the element cannot be read from. Reading `element.value` is not
12
+ * reactive, so a caller that does not already remeasure when its own text moves passes
13
+ * the value it holds here.
14
+ */
15
+ content?: MaybeRefOrGetter<unknown>;
16
+ }
17
+ export interface UseTextareaAutosizeSyncOptions {
18
+ /**
19
+ * From `input` only. A caret at the end then keeps the last line's padding in view.
20
+ * Layout remeasures omit this so a scroll the user made is not stolen.
21
+ */
22
+ fromInput?: boolean;
23
+ }
24
+ export interface UseTextareaAutosizeReturn {
25
+ /** Measure now. Needed from `input`, where the DOM already holds the next text. */
26
+ sync: (options?: UseTextareaAutosizeSyncOptions) => void;
27
+ }
28
+ /**
29
+ * Keep a textarea as tall as its content, optionally between `minRows` and `maxRows`.
30
+ *
31
+ * The caller has to invoke {@link UseTextareaAutosizeReturn.sync} from `input`: reading
32
+ * `element.value` inside a getter is not a reactive dependency, and waiting for a post-flush
33
+ * watch would size against the previous stroke. `minRows`, `maxRows` and {@link
34
+ * UseTextareaAutosizeOptions.content} go through a post-flush watch instead.
35
+ *
36
+ * Observers attach only while autosize is on. Native `resize` writes inline `width` and
37
+ * `height` as the pointer drags; an observer that stayed attached with autosize off would
38
+ * `clear` that height on every width change and fight the handle.
39
+ *
40
+ * Writing `style.height` is itself a size change, so the observer has to discriminate width
41
+ * or it would loop. That makes the seed load-bearing: it is read from the same content box
42
+ * `contentRect` reports, because a seed off by the border makes the first delivery look like
43
+ * a width change, and skipping that first delivery instead loses a real one — `sync` after
44
+ * `observe` can make a scrollbar appear, and the callback reporting the narrower width is
45
+ * the only notice of it.
46
+ *
47
+ * An inline height also hides height-only metric changes from the observer — a webfont that
48
+ * lands after first paint, or `.rp-textarea`'s `@media (width >= 40rem)` type/padding switch
49
+ * on a fixed-width control. Those go through `document.fonts` and `window` `resize`. Used
50
+ * metrics that do not move the box (`--rp-leading`, Firefox text-only zoom) never notify at
51
+ * all, which is why every field settles with `overflow-y: auto` — a stale height then
52
+ * scrolls rather than clips. A leftover clip on a field no cap clamped is the observer
53
+ * backstop for same-width box changes such as padding, which do notify.
54
+ */
55
+ export declare const useTextareaAutosize: (options: UseTextareaAutosizeOptions) => UseTextareaAutosizeReturn;