orio-ui 1.24.0 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/components/Button.d.vue.ts +3 -2
  4. package/dist/runtime/components/Button.vue +19 -11
  5. package/dist/runtime/components/Button.vue.d.ts +3 -2
  6. package/dist/runtime/components/Calendar.USAGE.md +51 -0
  7. package/dist/runtime/components/Calendar.vue +254 -87
  8. package/dist/runtime/components/Canvas/USAGE.md +65 -0
  9. package/dist/runtime/components/CheckBox.vue +9 -3
  10. package/dist/runtime/components/CheckboxGroup.vue +7 -1
  11. package/dist/runtime/components/ControlElement.USAGE.md +69 -0
  12. package/dist/runtime/components/ControlElement.d.vue.ts +42 -27
  13. package/dist/runtime/components/ControlElement.vue +28 -9
  14. package/dist/runtime/components/ControlElement.vue.d.ts +42 -27
  15. package/dist/runtime/components/Input.USAGE.md +49 -0
  16. package/dist/runtime/components/Input.vue +13 -3
  17. package/dist/runtime/components/Modal.USAGE.md +64 -0
  18. package/dist/runtime/components/NavButton.d.vue.ts +0 -1
  19. package/dist/runtime/components/NavButton.vue +9 -5
  20. package/dist/runtime/components/NavButton.vue.d.ts +0 -1
  21. package/dist/runtime/components/NumberInput/Horizontal.vue +7 -2
  22. package/dist/runtime/components/NumberInput/Vertical.vue +7 -2
  23. package/dist/runtime/components/NumberInput/index.d.vue.ts +0 -2
  24. package/dist/runtime/components/NumberInput/index.vue +9 -7
  25. package/dist/runtime/components/NumberInput/index.vue.d.ts +0 -2
  26. package/dist/runtime/components/RadioButton.d.vue.ts +0 -2
  27. package/dist/runtime/components/RadioButton.vue +9 -4
  28. package/dist/runtime/components/RadioButton.vue.d.ts +0 -2
  29. package/dist/runtime/components/Selector.d.vue.ts +1 -0
  30. package/dist/runtime/components/Selector.vue +10 -4
  31. package/dist/runtime/components/Selector.vue.d.ts +1 -0
  32. package/dist/runtime/components/SwitchButton.d.vue.ts +1 -4
  33. package/dist/runtime/components/SwitchButton.vue +10 -7
  34. package/dist/runtime/components/SwitchButton.vue.d.ts +1 -4
  35. package/dist/runtime/components/TaggableSelector.vue +7 -1
  36. package/dist/runtime/components/Textarea.vue +13 -3
  37. package/dist/runtime/components/date/Picker.USAGE.md +44 -0
  38. package/dist/runtime/components/date/Picker.vue +7 -1
  39. package/dist/runtime/components/date/PickerTrigger.vue +9 -3
  40. package/dist/runtime/components/date/RangePicker.vue +7 -1
  41. package/dist/runtime/composables/useFilter.d.ts +91 -0
  42. package/dist/runtime/composables/useFilter.js +111 -0
  43. package/dist/runtime/composables/useRovingGrid.d.ts +35 -0
  44. package/dist/runtime/composables/useRovingGrid.js +115 -0
  45. package/dist/runtime/i18n/en.json +4 -1
  46. package/dist/runtime/i18n/uk.json +4 -1
  47. package/package.json +1 -1
@@ -10,19 +10,25 @@ const props = defineProps({
10
10
  label: { type: String, required: false },
11
11
  layout: { type: String, required: false },
12
12
  size: { type: String, required: false },
13
- fill: { type: Boolean, required: false }
13
+ fill: { type: Boolean, required: false },
14
+ tabindex: { type: [Number, String], required: false },
15
+ focusKey: { type: String, required: false },
16
+ disabled: { type: Boolean, required: false },
17
+ required: { type: Boolean, required: false },
18
+ name: { type: String, required: false },
19
+ ariaLabel: { type: String, required: false }
14
20
  });
15
21
  </script>
16
22
 
17
23
  <template>
18
- <orio-control-element v-bind="props" class="checkbox" fill>
24
+ <orio-control-element v-slot="{ control }" v-bind="props" class="checkbox" fill>
19
25
  <label class="checkbox-label">
20
26
  <input
21
27
  v-model="modelValue"
28
+ v-bind="{ ...$attrs, ...control }"
22
29
  type="checkbox"
23
30
  class="checkbox-input"
24
31
  tabindex="-1"
25
- v-bind="$attrs"
26
32
  />
27
33
  <span
28
34
  class="checkbox-box"
@@ -6,7 +6,13 @@ const props = defineProps({
6
6
  label: { type: String, required: false },
7
7
  layout: { type: String, required: false, default: "vertical" },
8
8
  size: { type: String, required: false, default: "md" },
9
- fill: { type: Boolean, required: false }
9
+ fill: { type: Boolean, required: false },
10
+ tabindex: { type: [Number, String], required: false },
11
+ focusKey: { type: String, required: false },
12
+ disabled: { type: Boolean, required: false },
13
+ required: { type: Boolean, required: false },
14
+ name: { type: String, required: false },
15
+ ariaLabel: { type: String, required: false }
10
16
  });
11
17
  const modelValue = defineModel({ type: Array, ...{ default: () => [] } });
12
18
  function isChecked(value) {
@@ -0,0 +1,69 @@
1
+ # ControlElement — agent-only invariants
2
+
3
+ `ControlElement` is the wrapper every form input uses (Input, Textarea,
4
+ NumberInput, Selector, CheckBox, etc.). When you build a new orio form
5
+ component, wrap it in `<orio-control-element>`. When you consume an existing
6
+ one, pass `ControlProps` straight through — they are usually re-exported.
7
+
8
+ ## Invariants
9
+
10
+ - **`inheritAttrs: false`.** Attrs do **not** auto-flow onto the wrapper or
11
+ the inner element. The component exposes a `control` slot prop containing
12
+ the a11y/form attr bag (`id`, `ariaDescribedby`, `ariaInvalid`,
13
+ `ariaRequired`, plus passthrough `tabindex`, `focusKey`, `disabled`,
14
+ `required`, `name`, `ariaLabel`). The inner element **must** spread it:
15
+ ```vue
16
+ <orio-control-element v-slot="{ control }" v-bind="props">
17
+ <input v-bind="control" />
18
+ </orio-control-element>
19
+ ```
20
+ - **`group` prop changes the semantic root.** When `true`, the wrapper gets
21
+ `role="group"` + `aria-labelledby`, and the label renders as `<span>`
22
+ (still id-linked) instead of `<label>`. Use this for `CheckboxGroup`,
23
+ radio groups, anything where the "control" is multiple inputs.
24
+ - **Error wiring is automatic.** Setting `error` to a non-null string:
25
+ - Renders a `.control-error` span below the slot.
26
+ - Sets `aria-invalid` and `aria-describedby` on the inner element via the
27
+ `control` slot prop.
28
+ - Adds a red border to `.slot-wrapper` (unless the wrapper contains a
29
+ `:deep(.error-fields)` element, in which case the inner component owns
30
+ error styling — see TaggableSelector).
31
+ - **`size` is provided to descendants** via `provideControlSize`. Children
32
+ that use `useControlSize()` (e.g. inner buttons, icons) inherit it
33
+ automatically — do not re-pass `size` down manually.
34
+ - **`appearance="minimal"`** zeros margin and strips border + box-shadow from
35
+ the first slot child. Use for inputs embedded in a row with their own
36
+ surrounding chrome.
37
+
38
+ ## Gotchas
39
+
40
+ - The slot's `id` matches what the `<label>` points to via `for`. The inner
41
+ element receives the same `id` through the `control` bag. Do **not**
42
+ override it — it is `useId()` by default and accessibility breaks if two
43
+ inputs in the same render share an id.
44
+ - `disabled` is forwarded to the inner element AND drives the wrapper's
45
+ `.disabled` class for styling. Pass `disabled` on the wrapper, never on the
46
+ inner element directly.
47
+ - The exported types are the contract:
48
+ - `ControlProps` — what consumers pass to ControlElement.
49
+ - `ControlPassthroughProps` — the subset that travels to the inner element.
50
+ - `ControlSlotAttrs` — the bag exposed via the `control` slot prop.
51
+ - `ControlLayout = "vertical" | "horizontal"`.
52
+ Components that wrap ControlElement extend `ControlProps`, e.g.
53
+ `interface Props extends ControlProps { ... }`.
54
+
55
+ ## Quick reference
56
+
57
+ ```vue
58
+ <script setup lang="ts">
59
+ import type { ControlProps } from "./ControlElement.vue";
60
+ interface Props extends ControlProps { /* component-specific props */ }
61
+ const props = defineProps<Props>();
62
+ </script>
63
+
64
+ <template>
65
+ <orio-control-element v-slot="{ control }" v-bind="props">
66
+ <my-inner-element v-bind="control" />
67
+ </orio-control-element>
68
+ </template>
69
+ ```
@@ -1,43 +1,58 @@
1
1
  export type ControlLayout = "vertical" | "horizontal";
2
2
  export type ControlSize = "sm" | "md" | "lg" | "xl";
3
- export interface ControlProps {
4
- /**
5
- * Minimal will reset margin and remove border and box shadow from every element inside the slot
6
- */
3
+ /**
4
+ * A11y + form attrs that flow from the caller through ControlElement to the
5
+ * actual interactive element via the `control` slot prop. Never rendered on
6
+ * the wrapper itself.
7
+ */
8
+ export interface ControlPassthroughProps {
9
+ /** Native `tabindex` for the inner element. */
10
+ tabindex?: number | string;
11
+ /** Roving-focus identifier — see useRovingGrid. Rendered as `focus-key` DOM attr. */
12
+ focusKey?: string;
13
+ /** Disables the inner element AND drives wrapper disabled styling. */
14
+ disabled?: boolean;
15
+ /** Marks the inner element required and sets `aria-required`. */
16
+ required?: boolean;
17
+ /** Native `name` attribute for the inner form element. */
18
+ name?: string;
19
+ /** Accessible name for the inner element when no visible label is set. */
20
+ ariaLabel?: string;
21
+ }
22
+ export interface ControlProps extends ControlPassthroughProps {
23
+ /** Minimal resets margin and removes border/box-shadow from every element inside the slot. */
7
24
  appearance?: "normal" | "minimal";
8
- /**
9
- * Error message to display below the control
10
- */
25
+ /** Error message to display below the control. Also drives `aria-invalid` and `aria-describedby` on the inner element. */
11
26
  error?: string | null;
12
- /**
13
- * Marks this control as a group (adds role="group" and aria-labelledby).
14
- * The label renders as a <span> instead of <label>.
15
- * Use for groups of related controls (e.g. CheckboxGroup).
16
- */
27
+ /** Marks this control as a group (adds role="group" + aria-labelledby on the wrapper). The label renders as a <span> instead of <label>. Use for groups of related controls (e.g. CheckboxGroup). */
17
28
  group?: boolean;
18
- /**
19
- * ID for the control's form element, auto-generated if not provided
20
- */
29
+ /** ID for the inner form element. Auto-generated if not provided. */
21
30
  id?: string;
22
- /**
23
- * Label text for the control (or legend text when group is true)
24
- */
31
+ /** Label text for the control (or legend text when group is true). */
25
32
  label?: string;
26
- /**
27
- * Label position relative to the control
28
- */
33
+ /** Label position relative to the control. */
29
34
  layout?: ControlLayout;
30
- /**
31
- * Size of the control and its inner elements
32
- */
35
+ /** Size of the control and its inner elements. */
33
36
  size?: ControlSize;
34
- /**
35
- * Whether element should fill the container
36
- */
37
+ /** Whether the element should fill the container. */
37
38
  fill?: boolean;
38
39
  }
40
+ /**
41
+ * Bag the consumer spreads onto the inner interactive element via the `control`
42
+ * slot prop: `<input v-bind="control" />`. Extends the caller-facing
43
+ * passthrough props with attrs derived from ControlElement state
44
+ * (`aria-invalid` from `error`, `aria-describedby` pointing at the error span,
45
+ * etc.) and the required `id`.
46
+ */
47
+ export interface ControlSlotAttrs extends ControlPassthroughProps {
48
+ id: string;
49
+ ariaDescribedby?: string;
50
+ ariaInvalid?: boolean;
51
+ ariaRequired?: boolean;
52
+ }
39
53
  declare var __VLS_7: {
40
54
  id: string;
55
+ control: ControlSlotAttrs;
41
56
  };
42
57
  type __VLS_Slots = {} & {
43
58
  default?: (props: typeof __VLS_7) => any;
@@ -10,10 +10,29 @@ const props = defineProps({
10
10
  label: { type: String, required: false },
11
11
  layout: { type: String, required: false, default: "vertical" },
12
12
  size: { type: String, required: false, default: "md" },
13
- fill: { type: Boolean, required: false, default: false }
13
+ fill: { type: Boolean, required: false, default: false },
14
+ tabindex: { type: [Number, String], required: false },
15
+ focusKey: { type: String, required: false },
16
+ disabled: { type: Boolean, required: false },
17
+ required: { type: Boolean, required: false },
18
+ name: { type: String, required: false },
19
+ ariaLabel: { type: String, required: false }
14
20
  });
15
21
  provideControlSize(toRef(props, "size"));
16
22
  const sizeStyle = computed(() => sizeTokens[props.size]);
23
+ const errorId = computed(() => props.error ? `${props.id}-error` : void 0);
24
+ const control = computed(() => ({
25
+ id: props.id,
26
+ tabindex: props.tabindex,
27
+ focusKey: props.focusKey,
28
+ disabled: props.disabled || void 0,
29
+ required: props.required || void 0,
30
+ name: props.name,
31
+ ariaLabel: props.ariaLabel,
32
+ ariaDescribedby: errorId.value,
33
+ ariaInvalid: props.error ? true : void 0,
34
+ ariaRequired: props.required || void 0
35
+ }));
17
36
  </script>
18
37
 
19
38
  <template>
@@ -23,13 +42,13 @@ const sizeStyle = computed(() => sizeTokens[props.size]);
23
42
  appearance,
24
43
  layout,
25
44
  `size-${size}`,
26
- { 'has-error': error, group, fill }
45
+ { 'has-error': error, group, fill, disabled },
46
+ $attrs.class
27
47
  ]"
28
- :style="sizeStyle"
29
- v-bind="{
30
- ...$attrs,
31
- ...group ? { role: 'group', ...label ? { 'aria-labelledby': id } : {} } : {}
32
- }"
48
+ :style="[sizeStyle, $attrs.style]"
49
+ v-bind="
50
+ group ? { role: 'group', ...label ? { 'aria-labelledby': id } : {} } : {}
51
+ "
33
52
  >
34
53
  <component
35
54
  :is="group ? 'span' : 'label'"
@@ -41,9 +60,9 @@ const sizeStyle = computed(() => sizeTokens[props.size]);
41
60
  </component>
42
61
  <div class="control-group">
43
62
  <div class="slot-wrapper">
44
- <slot :id />
63
+ <slot :id :control />
45
64
  </div>
46
- <span v-if="error" class="control-error">{{ error }}</span>
65
+ <span v-if="error" :id="errorId" class="control-error">{{ error }}</span>
47
66
  </div>
48
67
  </div>
49
68
  </template>
@@ -1,43 +1,58 @@
1
1
  export type ControlLayout = "vertical" | "horizontal";
2
2
  export type ControlSize = "sm" | "md" | "lg" | "xl";
3
- export interface ControlProps {
4
- /**
5
- * Minimal will reset margin and remove border and box shadow from every element inside the slot
6
- */
3
+ /**
4
+ * A11y + form attrs that flow from the caller through ControlElement to the
5
+ * actual interactive element via the `control` slot prop. Never rendered on
6
+ * the wrapper itself.
7
+ */
8
+ export interface ControlPassthroughProps {
9
+ /** Native `tabindex` for the inner element. */
10
+ tabindex?: number | string;
11
+ /** Roving-focus identifier — see useRovingGrid. Rendered as `focus-key` DOM attr. */
12
+ focusKey?: string;
13
+ /** Disables the inner element AND drives wrapper disabled styling. */
14
+ disabled?: boolean;
15
+ /** Marks the inner element required and sets `aria-required`. */
16
+ required?: boolean;
17
+ /** Native `name` attribute for the inner form element. */
18
+ name?: string;
19
+ /** Accessible name for the inner element when no visible label is set. */
20
+ ariaLabel?: string;
21
+ }
22
+ export interface ControlProps extends ControlPassthroughProps {
23
+ /** Minimal resets margin and removes border/box-shadow from every element inside the slot. */
7
24
  appearance?: "normal" | "minimal";
8
- /**
9
- * Error message to display below the control
10
- */
25
+ /** Error message to display below the control. Also drives `aria-invalid` and `aria-describedby` on the inner element. */
11
26
  error?: string | null;
12
- /**
13
- * Marks this control as a group (adds role="group" and aria-labelledby).
14
- * The label renders as a <span> instead of <label>.
15
- * Use for groups of related controls (e.g. CheckboxGroup).
16
- */
27
+ /** Marks this control as a group (adds role="group" + aria-labelledby on the wrapper). The label renders as a <span> instead of <label>. Use for groups of related controls (e.g. CheckboxGroup). */
17
28
  group?: boolean;
18
- /**
19
- * ID for the control's form element, auto-generated if not provided
20
- */
29
+ /** ID for the inner form element. Auto-generated if not provided. */
21
30
  id?: string;
22
- /**
23
- * Label text for the control (or legend text when group is true)
24
- */
31
+ /** Label text for the control (or legend text when group is true). */
25
32
  label?: string;
26
- /**
27
- * Label position relative to the control
28
- */
33
+ /** Label position relative to the control. */
29
34
  layout?: ControlLayout;
30
- /**
31
- * Size of the control and its inner elements
32
- */
35
+ /** Size of the control and its inner elements. */
33
36
  size?: ControlSize;
34
- /**
35
- * Whether element should fill the container
36
- */
37
+ /** Whether the element should fill the container. */
37
38
  fill?: boolean;
38
39
  }
40
+ /**
41
+ * Bag the consumer spreads onto the inner interactive element via the `control`
42
+ * slot prop: `<input v-bind="control" />`. Extends the caller-facing
43
+ * passthrough props with attrs derived from ControlElement state
44
+ * (`aria-invalid` from `error`, `aria-describedby` pointing at the error span,
45
+ * etc.) and the required `id`.
46
+ */
47
+ export interface ControlSlotAttrs extends ControlPassthroughProps {
48
+ id: string;
49
+ ariaDescribedby?: string;
50
+ ariaInvalid?: boolean;
51
+ ariaRequired?: boolean;
52
+ }
39
53
  declare var __VLS_7: {
40
54
  id: string;
55
+ control: ControlSlotAttrs;
41
56
  };
42
57
  type __VLS_Slots = {} & {
43
58
  default?: (props: typeof __VLS_7) => any;
@@ -0,0 +1,49 @@
1
+ # Input — agent-only invariants
2
+
3
+ `<orio-input>` is the text input wrapping `ControlElement`. Read
4
+ `ControlElement.USAGE.md` first — most of the contract lives there.
5
+
6
+ ## Invariants
7
+
8
+ - **Extends `ControlProps`** with one override: `layout?: InputLayout` where
9
+ `InputLayout = ControlLayout | "inner"`. The extra `"inner"` is an
10
+ Input-specific mode that floats the label inside the input chrome.
11
+ - **`layout="inner"` translates internally** to `layout="vertical"` on
12
+ ControlElement and adds an `.inner` class on the wrapper. The label
13
+ reposition is driven by `:deep()` styles on ControlElement internals — no
14
+ duplicate label DOM is created.
15
+ - **The `control` slot bag is spread onto the inner `<input>`** alongside
16
+ `$attrs`: `v-bind="{ ...$attrs, ...control }"`. Attrs like `type`,
17
+ `autocomplete`, `placeholder`, `inputmode` work on `<orio-input>` and land
18
+ on the underlying `<input>`.
19
+ - **v-model is `string`** (default `""`). For numeric input use
20
+ `<orio-number-input>` instead.
21
+
22
+ ## Gotchas
23
+
24
+ - The `.slot-wrapper` uses `display: flex; align-items: center;` so `before`
25
+ and `after` slots sit inline with the input. Don't add wrapping divs inside
26
+ those slots — they'll break alignment.
27
+ - `:placeholder-shown` is used internally for the inner-label "empty" state.
28
+ If you pass an empty placeholder, the inner-label trick still works because
29
+ the wrapper sets `placeholder=" "` upstream when needed.
30
+ - The default browser input border is removed; the visible border lives on
31
+ `.slot-wrapper`. Custom inputs swapped in via slots will not inherit it —
32
+ prefer `before`/`after` slots over replacing the input.
33
+
34
+ ## Quick reference
35
+
36
+ ```vue
37
+ <orio-input
38
+ v-model="email"
39
+ label="Email"
40
+ layout="inner"
41
+ type="email"
42
+ autocomplete="email"
43
+ :error="emailError"
44
+ >
45
+ <template #before>
46
+ <orio-icon name="mail" />
47
+ </template>
48
+ </orio-input>
49
+ ```
@@ -7,20 +7,30 @@ const props = defineProps({
7
7
  id: { type: String, required: false },
8
8
  label: { type: String, required: false },
9
9
  size: { type: String, required: false },
10
- fill: { type: Boolean, required: false }
10
+ fill: { type: Boolean, required: false },
11
+ tabindex: { type: [Number, String], required: false },
12
+ focusKey: { type: String, required: false },
13
+ disabled: { type: Boolean, required: false },
14
+ required: { type: Boolean, required: false },
15
+ name: { type: String, required: false },
16
+ ariaLabel: { type: String, required: false }
11
17
  });
12
18
  const modelValue = defineModel({ type: String, ...{ default: "" } });
13
19
  </script>
14
20
 
15
21
  <template>
16
22
  <orio-control-element
17
- v-slot="{ id }"
23
+ v-slot="{ control }"
18
24
  v-bind="props"
19
25
  :layout="layout === 'inner' ? 'vertical' : layout"
20
26
  :class="{ inner: layout === 'inner' }"
21
27
  >
22
28
  <slot name="before" />
23
- <input :id v-model="modelValue" type="text" v-bind="$attrs" />
29
+ <input
30
+ v-model="modelValue"
31
+ type="text"
32
+ v-bind="{ ...$attrs, ...control }"
33
+ />
24
34
  <slot name="after" />
25
35
  </orio-control-element>
26
36
  </template>
@@ -0,0 +1,64 @@
1
+ # Modal — agent-only invariants
2
+
3
+ `<orio-modal>` is the teleported overlay dialog.
4
+
5
+ ## Invariants
6
+
7
+ - **Teleported to `<body>`.** Renders outside the parent DOM subtree. Any
8
+ CSS that targets `.modal` from a parent will not apply; scope styles via
9
+ `:deep()` from a parent or write global styles.
10
+ - **`origin` prop drives the open animation.** Pass the `getBoundingClientRect`
11
+ of the element that triggered the open (e.g. the clicked button) to
12
+ animate the modal **from** that rect to centered. Pass `null` to fade in
13
+ at center with no scale-from.
14
+ - **`v-model:show`** controls visibility. Backdrop click closes (`@click.self`
15
+ on the overlay). The default close button (rendered when no `header`
16
+ slot is supplied) also toggles `show`.
17
+ - **Body scroll lock** is applied automatically while `show` is true, via
18
+ `useScrollLock` from `@vueuse/core`. SSR-safe: ref defaults to `false`
19
+ on the server.
20
+ - **Header/footer are auto-hidden** when no `title` prop and no
21
+ `#header`/`#footer` slot is present. The content section (`#default`)
22
+ always renders.
23
+
24
+ ## Gotchas
25
+
26
+ - Multiple modals stacked at once will all lock body scroll; closing one
27
+ releases the lock for all. If you nest modals, manage the lock yourself.
28
+ - `origin`'s `width` / `height` should be the trigger's rendered size, not
29
+ the modal's. The animation derives the inverse scale from
30
+ `width / modalWidth` — wrong size = visible jump.
31
+ - The component uses inline styles via direct `.style.transform`
32
+ assignment on the wrapper ref. Do not animate `transform` from outside;
33
+ the component will overwrite it on the next open.
34
+
35
+ ## Quick reference
36
+
37
+ ```vue
38
+ <script setup lang="ts">
39
+ import { ref } from "vue";
40
+ const open = ref(false);
41
+ const origin = ref<DOMRect | null>(null);
42
+
43
+ function trigger(event: MouseEvent) {
44
+ origin.value = (event.currentTarget as HTMLElement).getBoundingClientRect();
45
+ open.value = true;
46
+ }
47
+ </script>
48
+
49
+ <template>
50
+ <orio-button @click="trigger">Open settings</orio-button>
51
+
52
+ <orio-modal v-model:show="open" :origin="origin" title="Settings">
53
+ <p>Modal body…</p>
54
+ <template #footer>
55
+ <orio-button @click="open = false">Done</orio-button>
56
+ </template>
57
+ </orio-modal>
58
+ </template>
59
+ ```
60
+
61
+ ## Related
62
+
63
+ - `useModal` composable — programmatic open/close API without managing
64
+ `show` yourself. See `docs/composables/use-modal.md`.
@@ -1,7 +1,6 @@
1
1
  import type { ControlProps } from "./ControlElement.vue.js";
2
2
  interface Props extends ControlProps {
3
3
  icon?: string;
4
- disabled?: boolean;
5
4
  active?: boolean;
6
5
  }
7
6
  declare var __VLS_8: {}, __VLS_15: {};
@@ -2,7 +2,6 @@
2
2
  import { computed, toRefs, useSlots } from "vue";
3
3
  const props = defineProps({
4
4
  icon: { type: String, required: false },
5
- disabled: { type: Boolean, required: false },
6
5
  active: { type: Boolean, required: false, default: false },
7
6
  appearance: { type: String, required: false },
8
7
  error: { type: [String, null], required: false },
@@ -11,7 +10,13 @@ const props = defineProps({
11
10
  label: { type: String, required: false },
12
11
  layout: { type: String, required: false },
13
12
  size: { type: String, required: false },
14
- fill: { type: Boolean, required: false }
13
+ fill: { type: Boolean, required: false },
14
+ tabindex: { type: [Number, String], required: false },
15
+ focusKey: { type: String, required: false },
16
+ disabled: { type: Boolean, required: false },
17
+ required: { type: Boolean, required: false },
18
+ name: { type: String, required: false },
19
+ ariaLabel: { type: String, required: false }
15
20
  });
16
21
  const { disabled, active } = toRefs(props);
17
22
  const slots = useSlots();
@@ -28,11 +33,10 @@ function click(event) {
28
33
  </script>
29
34
 
30
35
  <template>
31
- <orio-control-element v-bind="props">
36
+ <orio-control-element v-slot="{ control }" v-bind="props">
32
37
  <button
33
- v-bind="$attrs"
38
+ v-bind="{ ...$attrs, ...control }"
34
39
  :class="{ 'icon-only': isIconOnly, active }"
35
- :disabled
36
40
  :aria-current="active ? 'page' : void 0"
37
41
  @click="click"
38
42
  >
@@ -1,7 +1,6 @@
1
1
  import type { ControlProps } from "./ControlElement.vue.js";
2
2
  interface Props extends ControlProps {
3
3
  icon?: string;
4
- disabled?: boolean;
5
4
  active?: boolean;
6
5
  }
7
6
  declare var __VLS_8: {}, __VLS_15: {};
@@ -6,14 +6,19 @@ defineProps({
6
6
  max: { type: Number, required: false, default: void 0 },
7
7
  step: { type: Number, required: false, default: 1 },
8
8
  decimalPlaces: { type: Number, required: false, default: 0 },
9
- disabled: { type: Boolean, required: false, default: false },
10
9
  appearance: { type: String, required: false },
11
10
  error: { type: [String, null], required: false },
12
11
  group: { type: Boolean, required: false },
13
12
  id: { type: String, required: false },
14
13
  label: { type: String, required: false },
15
14
  size: { type: String, required: false },
16
- fill: { type: Boolean, required: false }
15
+ fill: { type: Boolean, required: false },
16
+ tabindex: { type: [Number, String], required: false },
17
+ focusKey: { type: String, required: false },
18
+ disabled: { type: Boolean, required: false, default: false },
19
+ required: { type: Boolean, required: false },
20
+ name: { type: String, required: false },
21
+ ariaLabel: { type: String, required: false }
17
22
  });
18
23
  const modelValue = defineModel({ type: Number, ...{ default: 0 } });
19
24
  const { pressAndHold, stop } = usePressAndHold();
@@ -6,14 +6,19 @@ defineProps({
6
6
  max: { type: Number, required: false, default: void 0 },
7
7
  step: { type: Number, required: false, default: 1 },
8
8
  decimalPlaces: { type: Number, required: false, default: 0 },
9
- disabled: { type: Boolean, required: false, default: false },
10
9
  appearance: { type: String, required: false },
11
10
  error: { type: [String, null], required: false },
12
11
  group: { type: Boolean, required: false },
13
12
  id: { type: String, required: false },
14
13
  label: { type: String, required: false },
15
14
  size: { type: String, required: false },
16
- fill: { type: Boolean, required: false }
15
+ fill: { type: Boolean, required: false },
16
+ tabindex: { type: [Number, String], required: false },
17
+ focusKey: { type: String, required: false },
18
+ disabled: { type: Boolean, required: false, default: false },
19
+ required: { type: Boolean, required: false },
20
+ name: { type: String, required: false },
21
+ ariaLabel: { type: String, required: false }
17
22
  });
18
23
  const modelValue = defineModel({ type: Number, ...{ default: 0 } });
19
24
  const { pressAndHold, stop } = usePressAndHold();
@@ -6,7 +6,6 @@ export interface NumberInputProps extends Omit<ControlProps, "layout"> {
6
6
  max?: number;
7
7
  step?: number;
8
8
  decimalPlaces?: number;
9
- disabled?: boolean;
10
9
  }
11
10
  type __VLS_Props = NumberInputProps;
12
11
  declare function increase(): void;
@@ -30,7 +29,6 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
30
29
  "onUpdate:modelValue"?: ((value: number) => any) | undefined;
31
30
  }>, {
32
31
  layout: InputLayout;
33
- disabled: boolean;
34
32
  step: number;
35
33
  min: number;
36
34
  max: number;
@@ -6,14 +6,19 @@ const props = defineProps({
6
6
  max: { type: Number, required: false, default: void 0 },
7
7
  step: { type: Number, required: false, default: 1 },
8
8
  decimalPlaces: { type: Number, required: false, default: 0 },
9
- disabled: { type: Boolean, required: false, default: false },
10
9
  appearance: { type: String, required: false },
11
10
  error: { type: [String, null], required: false },
12
11
  group: { type: Boolean, required: false },
13
12
  id: { type: String, required: false },
14
13
  label: { type: String, required: false },
15
14
  size: { type: String, required: false },
16
- fill: { type: Boolean, required: false }
15
+ fill: { type: Boolean, required: false },
16
+ tabindex: { type: [Number, String], required: false },
17
+ focusKey: { type: String, required: false },
18
+ disabled: { type: Boolean, required: false },
19
+ required: { type: Boolean, required: false },
20
+ name: { type: String, required: false },
21
+ ariaLabel: { type: String, required: false }
17
22
  });
18
23
  const { min, max, step, decimalPlaces } = toRefs(props);
19
24
  const modelValue = defineModel({ type: Number, ...{ default: 0 } });
@@ -49,7 +54,6 @@ const controlProps = computed(() => {
49
54
  max: _max,
50
55
  step: _step,
51
56
  decimalPlaces: _decimalPlaces,
52
- disabled: _disabled,
53
57
  ...rest
54
58
  } = props;
55
59
  return rest;
@@ -64,19 +68,17 @@ const slotExpose = computed(() => ({
64
68
 
65
69
  <template>
66
70
  <orio-control-element
67
- v-slot="{ id }"
71
+ v-slot="{ control }"
68
72
  v-bind="controlProps"
69
73
  :layout="layout === 'inner' ? 'vertical' : layout"
70
74
  :class="{ inner: layout === 'inner' }"
71
75
  >
72
76
  <div class="wrapper">
73
77
  <input
74
- v-bind="$attrs"
75
- :id
78
+ v-bind="{ ...$attrs, ...control }"
76
79
  v-model="modelValue"
77
80
  type="number"
78
81
  class="number-input"
79
- :disabled
80
82
  :min
81
83
  :max
82
84
  :step