@webx-ui/core 0.14.3 → 0.16.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.
@@ -39,6 +39,7 @@ declare function __VLS_template(): {
39
39
  readonly showCount?: boolean | undefined;
40
40
  readonly autocomplete?: string | undefined;
41
41
  readonly ariaLabel?: string | undefined;
42
+ readonly localized?: boolean | undefined;
42
43
  readonly onChange?: ((value: string) => any) | undefined;
43
44
  readonly "onUpdate:modelValue"?: ((value: import('..').InputModelValue) => any) | undefined;
44
45
  readonly onInput?: ((value: string) => any) | undefined;
@@ -94,6 +95,7 @@ declare function __VLS_template(): {
94
95
  autocomplete: string;
95
96
  maxlength: number;
96
97
  showCount: boolean;
98
+ localized: boolean;
97
99
  }, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
98
100
  beforeCreate?: (() => void) | (() => void)[];
99
101
  created?: (() => void) | (() => void)[];
@@ -127,6 +129,7 @@ declare function __VLS_template(): {
127
129
  autocomplete: string;
128
130
  maxlength: number;
129
131
  showCount: boolean;
132
+ localized: boolean;
130
133
  }> & Omit<Readonly<{
131
134
  modelValue?: import('..').InputModelValue;
132
135
  } & import('..').InputProps> & Readonly<{
@@ -136,7 +139,7 @@ declare function __VLS_template(): {
136
139
  onClear?: (() => any) | undefined;
137
140
  onBlur?: ((event: FocusEvent) => any) | undefined;
138
141
  onFocus?: ((event: FocusEvent) => any) | undefined;
139
- }>, "input" | "select" | "blur" | "focus" | ("size" | "disabled" | "type" | "placeholder" | "ariaLabel" | "clearable" | "status" | "id" | "readonly" | "autocomplete" | "maxlength" | "showCount")> & {
142
+ }>, "input" | "select" | "blur" | "focus" | ("size" | "disabled" | "type" | "placeholder" | "ariaLabel" | "clearable" | "status" | "id" | "readonly" | "autocomplete" | "maxlength" | "showCount" | "localized")> & {
140
143
  focus: () => void | undefined;
141
144
  blur: () => void | undefined;
142
145
  select: () => void | undefined;
@@ -203,6 +206,7 @@ declare const __VLS_component: import('vue').DefineComponent<FileCardProps, {},
203
206
  readonly showCount?: boolean | undefined;
204
207
  readonly autocomplete?: string | undefined;
205
208
  readonly ariaLabel?: string | undefined;
209
+ readonly localized?: boolean | undefined;
206
210
  readonly onChange?: ((value: string) => any) | undefined;
207
211
  readonly "onUpdate:modelValue"?: ((value: import('..').InputModelValue) => any) | undefined;
208
212
  readonly onInput?: ((value: string) => any) | undefined;
@@ -258,6 +262,7 @@ declare const __VLS_component: import('vue').DefineComponent<FileCardProps, {},
258
262
  autocomplete: string;
259
263
  maxlength: number;
260
264
  showCount: boolean;
265
+ localized: boolean;
261
266
  }, {}, string, {}, import('vue').GlobalComponents, import('vue').GlobalDirectives, string, import('vue').ComponentProvideOptions> & {
262
267
  beforeCreate?: (() => void) | (() => void)[];
263
268
  created?: (() => void) | (() => void)[];
@@ -291,6 +296,7 @@ declare const __VLS_component: import('vue').DefineComponent<FileCardProps, {},
291
296
  autocomplete: string;
292
297
  maxlength: number;
293
298
  showCount: boolean;
299
+ localized: boolean;
294
300
  }> & Omit<Readonly<{
295
301
  modelValue?: import('..').InputModelValue;
296
302
  } & import('..').InputProps> & Readonly<{
@@ -300,7 +306,7 @@ declare const __VLS_component: import('vue').DefineComponent<FileCardProps, {},
300
306
  onClear?: (() => any) | undefined;
301
307
  onBlur?: ((event: FocusEvent) => any) | undefined;
302
308
  onFocus?: ((event: FocusEvent) => any) | undefined;
303
- }>, "input" | "select" | "blur" | "focus" | ("size" | "disabled" | "type" | "placeholder" | "ariaLabel" | "clearable" | "status" | "id" | "readonly" | "autocomplete" | "maxlength" | "showCount")> & {
309
+ }>, "input" | "select" | "blur" | "focus" | ("size" | "disabled" | "type" | "placeholder" | "ariaLabel" | "clearable" | "status" | "id" | "readonly" | "autocomplete" | "maxlength" | "showCount" | "localized")> & {
304
310
  focus: () => void | undefined;
305
311
  blur: () => void | undefined;
306
312
  select: () => void | undefined;
@@ -47,6 +47,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_PublicProps,
47
47
  autocomplete: string;
48
48
  maxlength: number;
49
49
  showCount: boolean;
50
+ localized: boolean;
50
51
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
51
52
  inputRef: HTMLInputElement;
52
53
  }, any>;
@@ -1,7 +1,8 @@
1
+ import { LocalizedFieldProps, LocalizedValue } from '../../composables/useLocalized';
1
2
  export type InputSize = 'sm' | 'md' | 'lg';
2
3
  export type InputStatus = 'default' | 'success' | 'warning' | 'error';
3
4
  export type InputNativeType = 'text' | 'password' | 'email' | 'number' | 'search' | 'tel' | 'url';
4
- export interface InputProps {
5
+ export interface InputProps extends LocalizedFieldProps {
5
6
  /** Overrides the id generated for the control (and used by a WxFormItem label). */
6
7
  id?: string;
7
8
  /** `type` attribute of the underlying `<input>`. */
@@ -21,7 +22,8 @@ export interface InputProps {
21
22
  /** Accessible label used when the input has no visible `<label>`. */
22
23
  ariaLabel?: string;
23
24
  }
24
- export type InputModelValue = string | number | undefined;
25
+ /** A record once `localized` is on — the same field, in every language the site publishes in. */
26
+ export type InputModelValue = string | number | LocalizedValue | undefined;
25
27
  export interface InputEmits {
26
28
  input: [value: string];
27
29
  change: [value: string];
@@ -0,0 +1,11 @@
1
+ import { LocaleOption } from '../../composables/useLocalized';
2
+ type __VLS_Props = {
3
+ locales: LocaleOption[];
4
+ active: string;
5
+ };
6
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
7
+ choose: (code: string) => any;
8
+ }, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
9
+ onChoose?: ((code: string) => any) | undefined;
10
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
11
+ export default _default;
@@ -0,0 +1,39 @@
1
+ import { LocaleOption } from '../../composables/useLocalized';
2
+ import { LocalesProps } from './types';
3
+ type __VLS_Props = LocalesProps;
4
+ type __VLS_PublicProps = {
5
+ 'locale'?: string | undefined;
6
+ } & __VLS_Props;
7
+ declare function __VLS_template(): {
8
+ attrs: Partial<{}>;
9
+ slots: {
10
+ default?(_: {
11
+ locale: undefined;
12
+ active: boolean;
13
+ }): any;
14
+ default?(_: {
15
+ locale: LocaleOption;
16
+ active: boolean;
17
+ }): any;
18
+ };
19
+ refs: {};
20
+ rootEl: HTMLDivElement;
21
+ };
22
+ type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
23
+ declare const __VLS_component: import('vue').DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
24
+ change: (code: string) => any;
25
+ "update:locale": (value: string | undefined) => any;
26
+ }, string, import('vue').PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
27
+ onChange?: ((code: string) => any) | undefined;
28
+ "onUpdate:locale"?: ((value: string | undefined) => any) | undefined;
29
+ }>, {
30
+ variant: import('./types').LocalesVariant;
31
+ locales: LocaleOption[];
32
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
33
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
34
+ export default _default;
35
+ type __VLS_WithTemplateSlots<T, S> = T & {
36
+ new (): {
37
+ $slots: S;
38
+ };
39
+ };
@@ -0,0 +1,2 @@
1
+ export { default as WxLocales } from './Locales';
2
+ export type * from './types';
@@ -0,0 +1,20 @@
1
+ import { LocaleOption } from '../../composables/useLocalized';
2
+ export type LocalesVariant = 'inline' | 'tabs';
3
+ export interface LocalesProps {
4
+ /**
5
+ * Languages to offer. Left out, the list provided by the panel is used — which is what a
6
+ * field does, so that a form does not repeat the site's settings on every control.
7
+ */
8
+ locales?: LocaleOption[];
9
+ /**
10
+ * `inline` tucks the selector into the top-right corner of what it wraps and folds down to
11
+ * the current language until it is pointed at — for a single field, where a row of tabs
12
+ * above every input would be louder than the inputs.
13
+ *
14
+ * `tabs` puts them in a row above, for a whole section edited one language at a time.
15
+ */
16
+ variant?: LocalesVariant;
17
+ }
18
+ export interface LocalesEmits {
19
+ change: [code: string];
20
+ }
@@ -47,6 +47,11 @@ declare const _default: <T extends TableRow = TableRow>(__VLS_props: NonNullable
47
47
  row: T;
48
48
  index: number;
49
49
  }) => unknown;
50
+ /** Buttons along the top of a card, where a row has no room for a column of them. */
51
+ 'card-actions'?: (props: {
52
+ row: T;
53
+ index: number;
54
+ }) => unknown;
50
55
  }> & {
51
56
  [key: `header-${string}`]: ((props: {
52
57
  column: TableColumn<T>;
@@ -70,6 +75,11 @@ declare const _default: <T extends TableRow = TableRow>(__VLS_props: NonNullable
70
75
  row: T;
71
76
  index: number;
72
77
  }) => unknown;
78
+ /** Buttons along the top of a card, where a row has no room for a column of them. */
79
+ 'card-actions'?: (props: {
80
+ row: T;
81
+ index: number;
82
+ }) => unknown;
73
83
  };
74
84
  emit: (((evt: "search", term: string) => void) & ((evt: "row-click", row: T, index: number, event: MouseEvent) => void) & ((evt: "sort-change", sort: TableSort | null) => void) & ((evt: "selection-change", keys: RowKey[], rows: T[]) => void) & ((evt: "expand-change", keys: RowKey[], rows: T[]) => void) & ((evt: "node-drop", event: import('./types').TableNodeDropEvent<T>) => void) & ((evt: "state-change", state: TableState) => void)) & (((evt: "update:page", value: number) => void) & ((evt: "update:perPage", value: number) => void) & ((evt: "update:selected", value: RowKey[]) => void) & ((evt: "update:expanded", value: RowKey[]) => void) & ((evt: "update:sort", value: TableSort | null) => void) & ((evt: "update:search", value: string) => void));
75
85
  }>) => import('vue').VNode & {
@@ -50,6 +50,21 @@ export interface TableColumn<T = TableRow> {
50
50
  cellClass?: string;
51
51
  /** Leaves the column out without changing the array. */
52
52
  hidden?: boolean;
53
+ /**
54
+ * Drops the column while the table is narrower than this.
55
+ *
56
+ * The alternative is a horizontal scrollbar, and a column somebody has to drag sideways to
57
+ * read is a column they will not read. Say it about the ones that can go — a date, a count —
58
+ * and the ones that identify the row stay whatever the width.
59
+ */
60
+ hideBelow?: number;
61
+ /**
62
+ * Leaves the column out of a card, where space is the scarce thing.
63
+ *
64
+ * A date somebody scans down a column is worth a line of its own on a wide screen and is the
65
+ * first thing to go on a narrow one.
66
+ */
67
+ hideOnCards?: boolean;
53
68
  }
54
69
  /**
55
70
  * One line of the summary under the table. `label` occupies every column ahead of the
@@ -158,6 +173,21 @@ export interface TableProps<T = TableRow> {
158
173
  expandableIf?: (row: T) => boolean;
159
174
  /** Lines under the table: totals, discounts, whatever the figures are. */
160
175
  summary?: TableSummaryRow[];
176
+ /**
177
+ * Below this width — of the table, not the window — each row is drawn as a card instead.
178
+ *
179
+ * A table narrower than about forty characters is a row of columns nobody can read, and on a
180
+ * phone that is every table. `0` turns it off and keeps the columns at any width.
181
+ */
182
+ cardsBelow?: number;
183
+ /**
184
+ * Drops the table's own margins around the header and the cards.
185
+ *
186
+ * On its own the table is a surface, and its search field and cards keep clear of its rounded
187
+ * edge. Inside a card the card keeps the margins already, and a second set puts the search
188
+ * field a step in from whatever the card has above it.
189
+ */
190
+ flush?: boolean;
161
191
  /**
162
192
  * Puts the pagination in the footer. On by default as soon as `data` is a paginator,
163
193
  * since a paginated response is a promise that there are more pages to reach.
@@ -31,6 +31,7 @@ declare const _default: import('vue').DefineComponent<__VLS_PublicProps, {
31
31
  readonly: boolean;
32
32
  maxlength: number;
33
33
  showCount: boolean;
34
+ localized: boolean;
34
35
  rows: number;
35
36
  autosize: boolean | import('./types').AutosizeOptions;
36
37
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
@@ -1,9 +1,10 @@
1
1
  import { ControlSize, ControlStatus } from '../../composables/useFormField';
2
+ import { LocalizedFieldProps, LocalizedValue } from '../../composables/useLocalized';
2
3
  export interface AutosizeOptions {
3
4
  minRows?: number;
4
5
  maxRows?: number;
5
6
  }
6
- export interface TextareaProps {
7
+ export interface TextareaProps extends LocalizedFieldProps {
7
8
  size?: ControlSize;
8
9
  status?: ControlStatus;
9
10
  id?: string;
@@ -22,7 +23,8 @@ export interface TextareaProps {
22
23
  /** Accessible label used when the field has no visible `<label>`. */
23
24
  ariaLabel?: string;
24
25
  }
25
- export type TextareaModelValue = string | undefined;
26
+ /** A record once `localized` is on — the same field, in every language the site publishes in. */
27
+ export type TextareaModelValue = string | LocalizedValue | undefined;
26
28
  export interface TextareaEmits {
27
29
  input: [value: string];
28
30
  change: [value: string];
@@ -48,6 +48,7 @@ export * from './Input';
48
48
  export * from './InputNumber';
49
49
  export * from './Kanban';
50
50
  export * from './Link';
51
+ export * from './Locales';
51
52
  export * from './ListDetail';
52
53
  export * from './Loading';
53
54
  export * from './Main';
@@ -0,0 +1,66 @@
1
+ import { ComputedRef, InjectionKey, Ref } from 'vue';
2
+ /**
3
+ * One language the *content* is written in — not the language the panel is drawn in.
4
+ *
5
+ * A panel in English routinely edits a site published in Ukrainian and Russian, so the two lists
6
+ * are unrelated: this one comes from the site's own settings.
7
+ */
8
+ export interface LocaleOption {
9
+ code: string;
10
+ /** What the selector shows. The code in capitals when nothing better is given. */
11
+ label?: string;
12
+ }
13
+ /** A field's value in every language it is written in: `{ uk: 'Двигуни', ru: 'Двигатели' }`. */
14
+ export type LocalizedValue = Record<string, string>;
15
+ export interface LocalesContext {
16
+ list: Ref<LocaleOption[]>;
17
+ /**
18
+ * The language being edited, shared by every field on the screen.
19
+ *
20
+ * One selector per field, all moving together: switching a page to Russian and then finding
21
+ * the field below still in Ukrainian is how half-translated records get saved.
22
+ */
23
+ active: Ref<string>;
24
+ }
25
+ export declare const localesKey: InjectionKey<LocalesContext>;
26
+ /**
27
+ * Tells every localized field below which languages the site publishes in.
28
+ *
29
+ * ```ts
30
+ * provideLocales(computed(() => admin.i18n.state.contentLocales))
31
+ * ```
32
+ */
33
+ export declare function provideLocales(list: Ref<LocaleOption[]> | ComputedRef<LocaleOption[]>): void;
34
+ export declare function useLocales(): LocalesContext;
35
+ /** The label a selector shows for a locale. */
36
+ export declare function localeLabel(locale: LocaleOption): string;
37
+ /**
38
+ * Reads a localized value for display: the asked-for language, then anything that is filled in.
39
+ *
40
+ * A record half-translated is the normal state of a site being worked on, and a blank cell in a
41
+ * table says less than the language that does have the words.
42
+ */
43
+ export declare function localizedValue(value: LocalizedValue | string | null | undefined, locale?: string, fallback?: string): string;
44
+ export interface LocalizedFieldProps {
45
+ /**
46
+ * Edits the value in every language the site publishes in, with a selector on the field.
47
+ *
48
+ * The model then carries `{ uk: '…', ru: '…' }` rather than a string.
49
+ */
50
+ localized?: boolean;
51
+ }
52
+ /**
53
+ * What a text control needs to render itself once per language.
54
+ *
55
+ * The non-localized case is the same code path with one nameless slot, so a control has one
56
+ * template rather than two that drift apart.
57
+ */
58
+ export declare function useLocalized(props: LocalizedFieldProps, model: Ref<unknown>): {
59
+ on: ComputedRef<boolean>;
60
+ active: import('vue').WritableComputedRef<string, string>;
61
+ slots: ComputedRef<(string | undefined)[]>;
62
+ list: Ref<LocaleOption[], LocaleOption[]>;
63
+ read: (code: string | undefined) => string;
64
+ write: (code: string | undefined, next: string) => void;
65
+ nameFor: (name: unknown, code: string | undefined) => string | undefined;
66
+ };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './components';
2
2
  export { WebxUI, type WebxUiOptions } from './plugin';
3
3
  export type { ControlSize, ControlStatus, ValidationErrors } from './composables/useFormField';
4
4
  export { useControlAttrs, type ControlAttrs } from './composables/useControlAttrs';
5
+ export { provideLocales, useLocales, useLocalized, localeLabel, localizedValue, localesKey, type LocaleOption, type LocalesContext, type LocalizedValue, type LocalizedFieldProps, } from './composables/useLocalized';
5
6
  export { useElementWidth } from './composables/useElementWidth';
6
7
  export { useToast, toast, toastQueue, dismissToast, removeToast, clearToasts, type ToastApi, type ToastHandle, type ToastOptions, type ToastRecord, type ToastType, type ToastAction, } from './composables/useToast';
7
8
  export { openModal, createModal, useModal, connectModals, modalKey, type ModalHandle, type ModalOptions, type ModalPromise, } from './composables/useModal';