@sewadah/selaras 0.8.0 → 0.9.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.
@@ -8,6 +8,8 @@ export const selectTheme = tv({
8
8
  // let the plain gray hover ring beat the primary one in the cascade,
9
9
  // since they're all equal-specificity pseudo-class/attribute selectors.
10
10
  trigger: "inline-flex w-full min-h-10 flex-wrap items-center gap-1.5 rounded-[var(--selaras-resolved-radius-md)] bg-[var(--selaras-resolved-surface-default)] px-3 py-1.5 text-sm ring-1 ring-inset ring-[var(--selaras-resolved-border-default)] outline-none transition-[color,background-color,box-shadow] not-focus:not-focus-within:not-data-[state=open]:hover:ring-[var(--selaras-resolved-border-hover)] hover:bg-[var(--selaras-resolved-surface-elevated)] focus:ring-2 focus:ring-[var(--_selaras-color-focus)] focus-within:ring-2 focus-within:ring-[var(--_selaras-color-focus)] data-[state=open]:ring-2 data-[state=open]:ring-[var(--_selaras-color-focus)] disabled:opacity-50 disabled:pointer-events-none",
11
+ leading: "absolute start-0 top-1/2 -translate-y-1/2 m-0 flex min-w-0 items-center gap-1 border-0 p-0 ps-2.5 text-sm text-[var(--selaras-resolved-text-muted)] disabled:opacity-50",
12
+ trailing: "absolute end-0 top-1/2 -translate-y-1/2 m-0 flex min-w-0 items-center gap-1 border-0 p-0 pe-1 text-sm text-[var(--selaras-resolved-text-muted)] disabled:opacity-50",
11
13
  value: "flex-1 truncate text-start text-[var(--selaras-resolved-text-default)] data-[placeholder]:text-[var(--selaras-resolved-text-muted)]",
12
14
  // Both chip display branches render a real Chip (see
13
15
  // ComboboxSelectBase.vue) instead of hand-rolled markup, styled/
@@ -51,6 +51,8 @@ export declare const textareaTheme: import("tailwind-variants").TVReturnType<{
51
51
  }, {
52
52
  root: string;
53
53
  base: string;
54
+ leading: string;
55
+ trailing: string;
54
56
  leadingIcon: string;
55
57
  trailingIcon: string;
56
58
  clear: string;
@@ -107,6 +109,8 @@ export declare const textareaTheme: import("tailwind-variants").TVReturnType<{
107
109
  }, {
108
110
  root: string;
109
111
  base: string;
112
+ leading: string;
113
+ trailing: string;
110
114
  leadingIcon: string;
111
115
  trailingIcon: string;
112
116
  clear: string;
@@ -163,6 +167,8 @@ export declare const textareaTheme: import("tailwind-variants").TVReturnType<{
163
167
  }, {
164
168
  root: string;
165
169
  base: string;
170
+ leading: string;
171
+ trailing: string;
166
172
  leadingIcon: string;
167
173
  trailingIcon: string;
168
174
  clear: string;
@@ -9,6 +9,8 @@ export const textareaTheme = tv({
9
9
  // way Input's own icons are - once content wraps past one line,
10
10
  // centering against the whole (variable) box height would drift the
11
11
  // icon away from the first line of text it's meant to sit beside.
12
+ leading: "absolute top-1 start-0 m-0 flex min-w-0 items-center gap-1 border-0 p-0 ps-2.5 text-sm text-[var(--selaras-resolved-text-muted)] disabled:opacity-50",
13
+ trailing: "absolute top-1 end-0 m-0 flex min-w-0 items-center gap-1 border-0 p-0 pe-1 text-sm text-[var(--selaras-resolved-text-muted)] disabled:opacity-50",
12
14
  leadingIcon: "absolute start-3 top-2.5 shrink-0 text-[var(--selaras-resolved-text-muted)]",
13
15
  trailingIcon: "absolute end-3 top-2.5 shrink-0 text-[var(--selaras-resolved-text-muted)]",
14
16
  clear: "absolute end-1 top-1 shrink-0 rounded-full"
@@ -97,6 +97,7 @@ export type { ThemeComponentRegistry, ThemeConfiguration, ThemeDefaults, ThemeUi
97
97
  export type { ArrowConfig, RoundedArrowConfig } from '../utils/arrow.js';
98
98
  export type { AutocompleteValue } from '../utils/autocomplete-contracts.js';
99
99
  export type { BuiltinColorName, ColorRecipe, ColorRecipeInput, ColorRole, RuntimeColorOverrides, RuntimeThemeMode, RuntimeTokenOverrides } from '../utils/color-registry.js';
100
+ export type { FieldAdornmentSlotProps } from '../utils/field-adornments.js';
100
101
  export type { FunctionalTokenOverrides, GeometryTokenOverrides, ThemeTokenOverrides } from '../utils/functional-tokens.js';
101
102
  export type { IconRegistry } from '../utils/icons.js';
102
103
  export { defaultIcons } from '../utils/icons.js';
@@ -0,0 +1,14 @@
1
+ import type { CSSProperties } from 'vue';
2
+ export interface FieldAdornmentSlotProps {
3
+ disabled: boolean;
4
+ size: 'sm' | 'md' | 'lg';
5
+ /** Button size that fits inside the field. */
6
+ buttonSize: 'sm' | 'md';
7
+ }
8
+ /** Reserve the rendered width of custom content, including dynamic suffixes. */
9
+ export declare function useFieldAdornments(): {
10
+ leading: import("vue").ShallowRef<HTMLElement | null, HTMLElement | null>;
11
+ trailing: import("vue").ShallowRef<HTMLElement | null, HTMLElement | null>;
12
+ padding: (hasLeading: boolean, hasTrailing: boolean, trailingExtra?: string) => CSSProperties | undefined;
13
+ clearOffset: () => CSSProperties;
14
+ };
@@ -0,0 +1,36 @@
1
+ import { shallowRef, watchEffect } from "vue";
2
+ export function useFieldAdornments() {
3
+ const leading = shallowRef(null);
4
+ const trailing = shallowRef(null);
5
+ const leadingWidth = shallowRef();
6
+ const trailingWidth = shallowRef();
7
+ watchEffect((onCleanup) => {
8
+ const start = leading.value;
9
+ const end = trailing.value;
10
+ function measure() {
11
+ leadingWidth.value = start ? `${start.getBoundingClientRect().width}px` : void 0;
12
+ trailingWidth.value = end ? `${end.getBoundingClientRect().width}px` : void 0;
13
+ }
14
+ measure();
15
+ if (!start && !end || typeof ResizeObserver === "undefined")
16
+ return;
17
+ const observer = new ResizeObserver(measure);
18
+ if (start)
19
+ observer.observe(start);
20
+ if (end)
21
+ observer.observe(end);
22
+ onCleanup(() => observer.disconnect());
23
+ }, { flush: "post" });
24
+ function padding(hasLeading, hasTrailing, trailingExtra = "0rem") {
25
+ if (!hasLeading && !hasTrailing)
26
+ return;
27
+ return {
28
+ paddingInlineStart: hasLeading ? `calc(${leadingWidth.value ?? "2rem"} + 0.5rem)` : void 0,
29
+ paddingInlineEnd: hasTrailing ? `calc(${trailingWidth.value ?? "2rem"} + 0.5rem + ${trailingExtra})` : void 0
30
+ };
31
+ }
32
+ function clearOffset() {
33
+ return { insetInlineEnd: `calc(${trailingWidth.value ?? "2rem"} + 0.25rem)` };
34
+ }
35
+ return { leading, trailing, padding, clearOffset };
36
+ }
@@ -2,6 +2,7 @@ import type { VariantProps } from 'tailwind-variants';
2
2
  import type { selectTheme, SelectThemeSlots } from '../theme/select.js';
3
3
  import type { RoundedArrowConfig } from './arrow.js';
4
4
  import type { ColorRole } from './color-registry.js';
5
+ import type { FieldAdornmentSlotProps } from './field-adornments.js';
5
6
  import type { OverlayPortal, OverlayPositioning } from './overlay.js';
6
7
  import type { UiProp } from './ui.js';
7
8
  export type SelectValue = string | number;
@@ -94,6 +95,8 @@ export interface SelectEmits<Entry extends SelectEntry = {
94
95
  'update:searchTerm': [value: string];
95
96
  }
96
97
  export interface SelectSlots<Entry extends SelectEntry, Key extends string = 'value'> {
98
+ 'leading'?: (props: FieldAdornmentSlotProps) => any;
99
+ 'trailing'?: (props: FieldAdornmentSlotProps) => any;
97
100
  'item'?: (props: {
98
101
  item: SelectEntryItem<Entry>;
99
102
  }) => any;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sewadah/selaras",
3
3
  "type": "module",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "description": "A UI component library for Nuxt, built on Reka UI and Tailwind v4",
6
6
  "author": "Wicaksana Pratama <wicaksanapratama@gmail.com>",
7
7
  "license": "MIT",
@@ -105,16 +105,17 @@
105
105
  ],
106
106
  "scripts": {
107
107
  "prepack": "nuxt-module-build build",
108
- "dev": "bun run docs:prepare && nuxt dev docs",
108
+ "dev": "bun run docs:prepare && bun run --cwd docs dev",
109
109
  "dev:build": "bun run docs:build",
110
110
  "dev:generate": "bun run docs:generate",
111
111
  "dev:preview": "bunx nuxt preview docs",
112
112
  "dev:prepare": "bun run docs:prepare",
113
- "docs:build": "nuxt build docs",
113
+ "docs:build": "bun run --cwd docs build",
114
114
  "docs:dev": "nuxt-module-build build --stub && bun run scripts/sync-workspace-dist.mjs && nuxt-module-build prepare && nuxt prepare packages/docs/preview && nuxt dev packages/docs/preview",
115
- "docs:generate": "nuxt generate docs",
115
+ "docs:generate": "bun run --cwd docs generate",
116
116
  "docs:prepare": "nuxt-module-build build --stub && bun run scripts/sync-workspace-dist.mjs && nuxt-module-build prepare && nuxt prepare docs",
117
117
  "docs:types": "cd docs && vue-tsc --noEmit",
118
+ "test:docs-seo": "node scripts/check-docs-seo.mjs",
118
119
  "release": "bun run release:both",
119
120
  "release:both": "bun run release:selaras && bun run release:docs",
120
121
  "release:selaras": "bun run lint && bun run test && (if [ -n \"$RELEASE_VERSION\" ]; then npx changelogen --bump -r \"$RELEASE_VERSION\"; elif [ \"${RELEASE_BUMP:-auto}\" = \"auto\" ]; then npx changelogen --bump; else npx changelogen --bump \"--$RELEASE_BUMP\"; fi) && bun run test:release && npm publish --access public && bash scripts/tag-and-push-release.sh selaras && changelogen gh release",
@@ -11,7 +11,7 @@ Use the existing Selaras catalog to compose the requested interface. Check docum
11
11
 
12
12
  If a Selaras MCP connection is available, start with `list_components` or `search_documentation`, then use `get_documentation` and `get_example` for matching APIs and examples. Its offline catalog follows the installed package version. Tools retrieve documentation; use the user's requirements to decide which components fit. Do not assume a missing MCP connection prevents the task.
13
13
 
14
- Without MCP, read the [documentation index](https://sewadahapp.github.io/selaras/llms.txt), then retrieve the relevant Markdown guides through its links. Each guide includes component contracts and Vue example source. Prefer targeted pages over loading `llms-full.txt` for every task.
14
+ Without MCP, read the [documentation index](https://selarasui.my.id/llms.txt), then retrieve the relevant Markdown guides through its links. Each guide includes component contracts and Vue example source. Prefer targeted pages over loading `llms-full.txt` for every task.
15
15
 
16
16
  If the project has Selaras installed, inspect its package version and existing Nuxt configuration first. Published web documentation may describe a newer version; confirm uncertain APIs against installed public types. Component names below use the default `S` prefix; the application can configure another prefix.
17
17
 
@@ -27,14 +27,14 @@ These are discovery hints, not substitute API definitions. Read the matching cat
27
27
 
28
28
  ## Integration and customization
29
29
 
30
- For a new integration, read [Installation](https://sewadahapp.github.io/selaras/raw/overview/getting-started/installation.md) and [Nuxt configuration](https://sewadahapp.github.io/selaras/raw/overview/getting-started/nuxt-configuration.md). Existing projects may already have providers and styles configured; inspect before changing them.
30
+ For a new integration, read [Installation](https://selarasui.my.id/raw/overview/getting-started/installation.md) and [Nuxt configuration](https://selarasui.my.id/raw/overview/getting-started/nuxt-configuration.md). Existing projects may already have providers and styles configured; inspect before changing them.
31
31
 
32
32
  - `SApp` supplies shared providers. Toast and CommandPalette still require the documented mounted components.
33
33
  - Use supported props for behavior and appearance, slots for custom content, `class` for the root, and `ui` for documented component parts.
34
- - Read [Theming](https://sewadahapp.github.io/selaras/raw/overview/theming/overview.md) for CSS tokens, global `app.config.selaras.ui` and defaults, or scoped `STheme`. Do not invent slot names or assume every prop has a global default.
35
- - Read [Icons](https://sewadahapp.github.io/selaras/raw/overview/getting-started/icons.md) for Nuxt Icon loading and configuration. Internal icon purposes use `app.config.selaras.icons`; explicitly supplied icons remain local.
36
- - Read [Messages](https://sewadahapp.github.io/selaras/raw/overview/getting-started/messages.md) for internal text and accessible labels. The formatting locale and translated messages are separate settings.
37
- - Read [Color modes](https://sewadahapp.github.io/selaras/raw/overview/theming/color-modes.md) for light, dark, and system preferences. Documentation showcase themes are not automatically installed application presets.
38
- - Read [Adaptive interfaces](https://sewadahapp.github.io/selaras/raw/overview/getting-started/adaptive-interfaces.md) before opting supported controls into mobile modal presentation. `adaptive` is opt-in, not a universal component prop.
34
+ - Read [Theming](https://selarasui.my.id/raw/overview/theming/overview.md) for CSS tokens, global `app.config.selaras.ui` and defaults, or scoped `STheme`. Do not invent slot names or assume every prop has a global default.
35
+ - Read [Icons](https://selarasui.my.id/raw/overview/getting-started/icons.md) for Nuxt Icon loading and configuration. Internal icon purposes use `app.config.selaras.icons`; explicitly supplied icons remain local.
36
+ - Read [Messages](https://selarasui.my.id/raw/overview/getting-started/messages.md) for internal text and accessible labels. The formatting locale and translated messages are separate settings.
37
+ - Read [Color modes](https://selarasui.my.id/raw/overview/theming/color-modes.md) for light, dark, and system preferences. Documentation showcase themes are not automatically installed application presets.
38
+ - Read [Adaptive interfaces](https://selarasui.my.id/raw/overview/getting-started/adaptive-interfaces.md) before opting supported controls into mobile modal presentation. `adaptive` is opt-in, not a universal component prop.
39
39
 
40
40
  Match item shapes, model values, and selection events to the component contract. Preserve accessible names, keyboard behavior, focus restoration, and form associations when customizing slots. Validate interactions relevant to the change in the project's normal checks, including mobile presentation when enabled.