@nexxtmove/ui 1.47.0 → 1.48.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.
@@ -0,0 +1,142 @@
1
+ /** One icon in the catalogue the consumer hands in. */
2
+ export interface NexxtIconPickerIcon {
3
+ /** Identity: stored on the model and handed to `iconClass`. */
4
+ name: string;
5
+ /** Shown in the trigger and the footer, read out as the cell's name, searched. */
6
+ label: string;
7
+ /** Extra search words, e.g. `home` for a house. */
8
+ terms: string[];
9
+ /** The ids of the styles the icon exists in; only these are ever drawn or written. */
10
+ styles: string[];
11
+ }
12
+ /** A category in the rail. */
13
+ export interface NexxtIconPickerCategory {
14
+ /** Identity of the category, unique within `categories`. */
15
+ id: string;
16
+ /** Text of the rail item; the rail sorts on it. */
17
+ label: string;
18
+ /** Names of the icons in the category; a name the catalogue does not know is skipped. */
19
+ icons: string[];
20
+ }
21
+ /** The section above "all icons", e.g. the icons already on the page. */
22
+ export interface NexxtIconPickerPinned {
23
+ /** Heading of the section, e.g. `'Op deze pagina'`. */
24
+ label: string;
25
+ /** Icon names. The current icon always leads the section; two rows at most. */
26
+ icons: string[];
27
+ }
28
+ /** A style the icons can be drawn in, with the classes that draw it. */
29
+ export interface NexxtIconPickerStyle {
30
+ /** Identity: what `NexxtIconPickerIcon.styles` lists and the model stores. */
31
+ id: string;
32
+ /** Shown behind the icon's label in the trigger, e.g. `'Light'`. */
33
+ label: string;
34
+ /** The classes that draw a glyph in this style, next to the class from `iconClass`. */
35
+ classes: readonly string[];
36
+ }
37
+ /** What the picker reads and writes. */
38
+ export interface NexxtIconPickerValue {
39
+ /** An icon `name`. */
40
+ icon: string;
41
+ /** A style `id`. */
42
+ style: string;
43
+ }
44
+ /** Overridable copy. Every key is optional and merged per key with the Dutch defaults. */
45
+ export interface NexxtIconPickerMessages {
46
+ /** In the trigger while there is no value. Defaults to `'Kies een icoon'`. */
47
+ placeholder?: string;
48
+ /** Placeholder of the search field. Defaults to `'Zoek in het Engels, bijv. house'`. */
49
+ searchPlaceholder?: string;
50
+ /** Accessible name of the search field. Defaults to `'Icoon zoeken'`. */
51
+ searchLabel?: string;
52
+ /** Accessible name of the category rail. Defaults to `'Categorieën'`. */
53
+ categoriesLabel?: string;
54
+ /** The first rail item, and the heading of the full list under a pinned section. Defaults to `'Alle iconen'`. */
55
+ allIcons?: string;
56
+ /** Read out as the description of the current icon. Defaults to `'Huidige keuze'`. */
57
+ current?: string;
58
+ /** Heading of the empty search state. Defaults to `'Geen iconen gevonden'`. */
59
+ emptyTitle?: string;
60
+ /** Line under the empty heading; receives the trimmed search term. */
61
+ emptyDescription?: (search: string) => string;
62
+ /** Button in the empty state that clears the search. Defaults to `'Zoekopdracht wissen'`. */
63
+ clearSearch?: string;
64
+ /** Notice under the grid when the catalogue could not be loaded. */
65
+ catalogueError?: string;
66
+ /** Button in that notice. Defaults to `'Opnieuw proberen'`. */
67
+ retry?: string;
68
+ /** Announced 500ms after a search or a category change; receives the number of icons. */
69
+ results?: (count: number) => string;
70
+ }
71
+ export interface NexxtIconPickerProps {
72
+ /** The catalogue. The component fetches nothing itself: load it on `@open`. */
73
+ icons: NexxtIconPickerIcon[];
74
+ /** The categories of the rail, after "Alle iconen"; sorted on label in `sortLocale`. */
75
+ categories: NexxtIconPickerCategory[];
76
+ /**
77
+ * A section above "Alle iconen" while there is no search and no category, e.g. the icons
78
+ * already on the page. The current icon always leads it; two rows at most. Not shown when it
79
+ * would be empty.
80
+ */
81
+ pinned?: NexxtIconPickerPinned;
82
+ /**
83
+ * The styles, in the order of preference: a cell shows its icon in the current style when the
84
+ * icon has it, otherwise in the first of these it has, and choosing it writes that style.
85
+ */
86
+ styles: NexxtIconPickerStyle[];
87
+ /**
88
+ * State of fetching the catalogue. `loading` shows skeletons while `icons` is empty; `error`
89
+ * shows a notice with a retry button. Without a catalogue the current icon stays the one
90
+ * choosable cell; a search typed meanwhile applies once the catalogue is in.
91
+ */
92
+ catalogueStatus?: 'loading' | 'ready' | 'error';
93
+ /**
94
+ * The class that picks an icon's glyph, next to the classes of its style. The component knows no
95
+ * icon set: for Font Awesome it returns the class of the named glyph.
96
+ */
97
+ iconClass: (name: string) => string;
98
+ /**
99
+ * Visible label above the trigger, for a form. Give this or `ariaLabel`: without either the
100
+ * trigger has no name for the field, and a development build warns in the console.
101
+ */
102
+ label?: string;
103
+ /**
104
+ * Accessible name when there is no visible label, as in the editor. The trigger reads it
105
+ * followed by the icon and its style: "Symbool, Star, Light". Give this or `label`.
106
+ */
107
+ ariaLabel?: string;
108
+ /**
109
+ * Copy of the trigger and the panel. Merged per key with the Dutch defaults, so overriding one
110
+ * key keeps the others. Copy is never translated inside the component.
111
+ */
112
+ messages?: NexxtIconPickerMessages;
113
+ /**
114
+ * Where the panel opens. `left` is for a picker in a side panel: the panel opens beside it, top
115
+ * aligned, and below it (right aligned) when the room on the left is less than the panel plus
116
+ * an 8px viewport margin.
117
+ */
118
+ side?: 'bottom' | 'left';
119
+ /** Distance between trigger and panel when it opens to the left, e.g. to clear a panel edge. */
120
+ sideOffset?: number;
121
+ /** Locale the rail and the grid sort their labels in. */
122
+ sortLocale?: string;
123
+ }
124
+ declare const _default: typeof __VLS_export;
125
+ export default _default;
126
+ declare const __VLS_export: import('vue').DefineComponent<NexxtIconPickerProps & {
127
+ /** The chosen icon and style. Only a choice writes the model; moving the highlight never does. */
128
+ modelValue?: NexxtIconPickerValue | null;
129
+ }, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
130
+ close: () => any;
131
+ "update:modelValue": (value: NexxtIconPickerValue | null) => any;
132
+ open: () => any;
133
+ retry: () => any;
134
+ }, string, import('vue').PublicProps, Readonly<NexxtIconPickerProps & {
135
+ /** The chosen icon and style. Only a choice writes the model; moving the highlight never does. */
136
+ modelValue?: NexxtIconPickerValue | null;
137
+ }> & Readonly<{
138
+ onClose?: (() => any) | undefined;
139
+ "onUpdate:modelValue"?: ((value: NexxtIconPickerValue | null) => any) | undefined;
140
+ onOpen?: (() => any) | undefined;
141
+ onRetry?: (() => any) | undefined;
142
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -0,0 +1,40 @@
1
+ import { IconPickerGridHandle } from './useIconPickerNavigation';
2
+ import { NexxtIconPickerIcon } from './IconPicker.vue';
3
+ import { GridPosition, GridRow } from './useIconPickerCatalogue';
4
+ interface IconPickerGridProps {
5
+ /** Every row of the list on show; only those in view (and the overscan) are rendered. */
6
+ rows: GridRow[];
7
+ /** Skeleton cells instead of the rows: the catalogue is on its way. */
8
+ skeleton?: boolean;
9
+ /** Id of the grid element, for the search field's `aria-controls`. */
10
+ gridId: string;
11
+ /** Id of the active tab that names the grid. */
12
+ labelledby: string;
13
+ /** A cell's id is this prefix, its row and its column. */
14
+ cellIdPrefix: string;
15
+ /** Id of the hidden "Huidige keuze", the description of the selected cell. */
16
+ currentDescriptionId: string;
17
+ /** The highlighted cell; drawn while the grid has focus. */
18
+ highlight: GridPosition | null;
19
+ /** Whether the grid has focus. */
20
+ focused: boolean;
21
+ /** The one selected cell: the first place of the current icon. */
22
+ selected: GridPosition | null;
23
+ /** The classes that draw an icon's glyph in the style a choice would write. */
24
+ glyphClass: (icon: NexxtIconPickerIcon) => string[];
25
+ }
26
+ declare const _default: typeof __VLS_export;
27
+ export default _default;
28
+ declare const __VLS_export: import('vue').DefineComponent<IconPickerGridProps, IconPickerGridHandle, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
29
+ focus: () => any;
30
+ blur: () => any;
31
+ keydown: (event: KeyboardEvent) => any;
32
+ hover: (position: GridPosition) => any;
33
+ choose: (icon: NexxtIconPickerIcon) => any;
34
+ }, string, import('vue').PublicProps, Readonly<IconPickerGridProps> & Readonly<{
35
+ onFocus?: (() => any) | undefined;
36
+ onBlur?: (() => any) | undefined;
37
+ onKeydown?: ((event: KeyboardEvent) => any) | undefined;
38
+ onHover?: ((position: GridPosition) => any) | undefined;
39
+ onChoose?: ((icon: NexxtIconPickerIcon) => any) | undefined;
40
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -0,0 +1,22 @@
1
+ import { RailTab } from './useIconPickerCatalogue';
2
+ interface IconPickerRailProps {
3
+ /** "Alle iconen" first, then the categories that hold an icon, sorted. */
4
+ tabs: RailTab[];
5
+ /** Index of the selected tab in `tabs`: the one tab stop. */
6
+ activeIndex: number;
7
+ /** Accessible name of the tablist. */
8
+ label: string;
9
+ /** Id of the tab panel every tab controls. */
10
+ panelId: string;
11
+ /** The id of the tab at an index; the tab panel and the grid are labelled by the active one. */
12
+ tabId: (index: number) => string;
13
+ /** Skeleton bars after the tabs: the categories are on their way. */
14
+ loading?: boolean;
15
+ }
16
+ declare const _default: typeof __VLS_export;
17
+ export default _default;
18
+ declare const __VLS_export: import('vue').DefineComponent<IconPickerRailProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
19
+ select: (id: string | null) => any;
20
+ }, string, import('vue').PublicProps, Readonly<IconPickerRailProps> & Readonly<{
21
+ onSelect?: ((id: string | null) => any) | undefined;
22
+ }>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
@@ -0,0 +1,39 @@
1
+ import { NexxtIconPickerIcon } from './IconPicker.vue';
2
+ /**
3
+ * The pure parts of `NexxtIconPicker`: the label of an icon outside the catalogue, the sort, the
4
+ * search and the style an icon is drawn in. Generic like the picker itself: no icon set, no class
5
+ * names.
6
+ */
7
+ /** The locale rail and grid sort in unless the consumer gives another. */
8
+ export declare const DEFAULT_SORT_LOCALE = "nl";
9
+ /** An icon in the search index: its words prepared once, not per keystroke. */
10
+ export interface NexxtIconPickerSearchEntry {
11
+ icon: NexxtIconPickerIcon;
12
+ /** The label, lower case. */
13
+ label: string;
14
+ /** Name, label and terms in one lower-case string, for the substring match. */
15
+ haystack: string;
16
+ /** The words of the name and the label, for "a word starts with". */
17
+ words: string[];
18
+ }
19
+ /**
20
+ * `house-chimney` → `House chimney`. What an icon is called while the catalogue that holds its
21
+ * label is not in yet, and the label a catalogue can derive for every icon whose label is just its
22
+ * name.
23
+ */
24
+ export declare const iconLabelFromName: (name: string) => string;
25
+ /** A sorted copy, alphabetical on label in `locale`. */
26
+ export declare const sortIconsByLabel: (icons: readonly NexxtIconPickerIcon[], locale?: string) => NexxtIconPickerIcon[];
27
+ /** Sorted by label, so the stable sort of a search keeps every rank in alphabetical order. */
28
+ export declare const iconSearchIndex: (icons: readonly NexxtIconPickerIcon[], locale?: string) => NexxtIconPickerSearchEntry[];
29
+ /**
30
+ * Every word of the search has to occur in the name, the label or the terms (AND, any case); the
31
+ * results come in the order of `searchRank`, alphabetical within a rank. An empty search finds
32
+ * nothing.
33
+ */
34
+ export declare const searchIcons: (index: readonly NexxtIconPickerSearchEntry[], search: string) => NexxtIconPickerIcon[];
35
+ /**
36
+ * The style an icon is drawn and chosen in: the given one when the icon has it, otherwise the
37
+ * first of `order` it has. `null` only for an icon that has none of the styles in `order`.
38
+ */
39
+ export declare const iconStyleFor: (styles: readonly string[], preferred: string | undefined, order: readonly string[]) => string | null;
@@ -0,0 +1,72 @@
1
+ import { MaybeRefOrGetter, Ref } from 'vue';
2
+ import { NexxtIconPickerCategory, NexxtIconPickerIcon, NexxtIconPickerPinned, NexxtIconPickerStyle, NexxtIconPickerValue } from './IconPicker.vue';
3
+ /**
4
+ * Six columns with a 12px gap (`gap-3`) scan more easily than eight close together. `grid-cols-6`
5
+ * in `_IconPickerGrid.vue` is the same number: change both together.
6
+ */
7
+ export declare const COLUMNS = 6;
8
+ /** A line of the grid: a section heading, or up to `COLUMNS` icons. */
9
+ export type GridRow = {
10
+ kind: 'heading';
11
+ key: string;
12
+ label: string;
13
+ } | {
14
+ kind: 'icons';
15
+ key: string;
16
+ icons: NexxtIconPickerIcon[];
17
+ };
18
+ /** A cell, by its index in the rows and its column. */
19
+ export interface GridPosition {
20
+ row: number;
21
+ col: number;
22
+ }
23
+ /** A rail item; `null` is "all icons". */
24
+ export interface RailTab {
25
+ id: string | null;
26
+ label: string;
27
+ }
28
+ interface IconPickerCatalogueOptions {
29
+ icons: MaybeRefOrGetter<NexxtIconPickerIcon[]>;
30
+ categories: MaybeRefOrGetter<NexxtIconPickerCategory[]>;
31
+ pinned: MaybeRefOrGetter<NexxtIconPickerPinned | undefined>;
32
+ styles: MaybeRefOrGetter<NexxtIconPickerStyle[]>;
33
+ /** A getter, never the function itself: `toValue` would call that without a name. */
34
+ iconClass: () => (name: string) => string;
35
+ sortLocale: MaybeRefOrGetter<string>;
36
+ /** Heading of the full list under a pinned section. */
37
+ allIconsLabel: MaybeRefOrGetter<string>;
38
+ model: Ref<NexxtIconPickerValue | null>;
39
+ /** The trimmed search. */
40
+ term: Ref<string>;
41
+ /** The chosen category; `null` is "all icons". */
42
+ category: Ref<string | null>;
43
+ }
44
+ /**
45
+ * What the picker shows, derived from the catalogue, the model, the search and the category: the
46
+ * rail's categories, the grid's rows and where the current icon is in them, and the classes that
47
+ * draw a glyph. No DOM, no focus: that is `useIconPickerNavigation` and the parts.
48
+ */
49
+ export declare const useIconPickerCatalogue: (options: IconPickerCatalogueOptions) => {
50
+ shownCategories: import('vue').ComputedRef<{
51
+ id: string;
52
+ label: string;
53
+ icons: NexxtIconPickerIcon[];
54
+ }[]>;
55
+ activeCategory: import('vue').ComputedRef<{
56
+ id: string;
57
+ label: string;
58
+ icons: NexxtIconPickerIcon[];
59
+ } | null>;
60
+ catalogueEmpty: import('vue').ComputedRef<boolean>;
61
+ currentIcon: import('vue').ComputedRef<NexxtIconPickerIcon | null>;
62
+ currentStyle: import('vue').ComputedRef<NexxtIconPickerStyle | null>;
63
+ rows: import('vue').ComputedRef<GridRow[]>;
64
+ iconRows: import('vue').ComputedRef<number[]>;
65
+ iconCount: import('vue').ComputedRef<number>;
66
+ currentPosition: import('vue').ComputedRef<GridPosition | null>;
67
+ rowLength: (row: number | undefined) => number;
68
+ iconAt: (position: GridPosition | null) => NexxtIconPickerIcon | null;
69
+ styleOf: (icon: NexxtIconPickerIcon) => string | null;
70
+ glyphClass: (icon: NexxtIconPickerIcon, style?: string | null) => string[];
71
+ };
72
+ export {};
@@ -0,0 +1,60 @@
1
+ import { ComputedRef, Ref } from 'vue';
2
+ import { NexxtIconPickerIcon } from './IconPicker.vue';
3
+ import { GridPosition } from './useIconPickerCatalogue';
4
+ /** What the grid part exposes: the parts of navigating that need its scroll box. */
5
+ export interface IconPickerGridHandle {
6
+ /** Focus the grid itself; the highlight is its active descendant. */
7
+ focus: () => void;
8
+ /** Scroll the least needed to show the row, and render the rows there at once. */
9
+ reveal: (row: number) => void;
10
+ /** Whether the row is fully in view. */
11
+ inView: (row: number) => boolean;
12
+ /** The rows that fit in view, less one, at least one. */
13
+ pageRows: () => number;
14
+ scrollToTop: () => void;
15
+ }
16
+ interface IconPickerNavigationOptions {
17
+ /** The indexes of the rows that hold icons, in order. */
18
+ iconRows: ComputedRef<number[]>;
19
+ currentPosition: ComputedRef<GridPosition | null>;
20
+ iconCount: ComputedRef<number>;
21
+ catalogueEmpty: ComputedRef<boolean>;
22
+ iconAt: (position: GridPosition | null) => NexxtIconPickerIcon | null;
23
+ rowLength: (row: number | undefined) => number;
24
+ /** The raw search: a letter typed in the grid is appended to it. */
25
+ search: Ref<string>;
26
+ /** The trimmed search. */
27
+ term: ComputedRef<string>;
28
+ category: Ref<string | null>;
29
+ isOpen: Ref<boolean>;
30
+ grid: () => IconPickerGridHandle | null | undefined;
31
+ focusSearch: () => void;
32
+ choose: (icon: NexxtIconPickerIcon) => void;
33
+ /** The copy of the announcement. */
34
+ results: () => (count: number) => string;
35
+ }
36
+ /**
37
+ * The keyboard, highlight and focus state of the picker: the highlighted cell and whether the grid
38
+ * has focus, the keys of the search field and the grid, the move from one to the other, and the
39
+ * results count for the live region. Only a choice writes the model; moving the highlight never does.
40
+ */
41
+ export declare const useIconPickerNavigation: (options: IconPickerNavigationOptions) => {
42
+ highlight: Ref<{
43
+ row: number;
44
+ col: number;
45
+ } | null, GridPosition | {
46
+ row: number;
47
+ col: number;
48
+ } | null>;
49
+ highlightedIcon: ComputedRef<NexxtIconPickerIcon | null>;
50
+ gridFocused: Ref<boolean, boolean>;
51
+ announcement: Ref<string, string>;
52
+ open: (reset: () => void) => void;
53
+ close: () => void;
54
+ onGridFocus: () => void;
55
+ onGridBlur: () => void;
56
+ onCellHover: (position: GridPosition) => void;
57
+ onGridKeydown: (event: KeyboardEvent) => void;
58
+ onSearchKeydown: (event: KeyboardEvent) => void;
59
+ };
60
+ export {};
package/dist/index.d.ts CHANGED
@@ -41,6 +41,9 @@ export type { EditorLetterSpacingMessages, EditorLetterSpacingValue, NexxtEditor
41
41
  export { EDITOR_FONT_SIZE_STEPS } from './components/editor/molecules/EditorFontSize/EditorFontSize.vue';
42
42
  export type { EditorFontSizeMessages, EditorFontSizeValue, NexxtEditorFontSizeProps, } from './components/editor/molecules/EditorFontSize/EditorFontSize.vue';
43
43
  export type { NexxtFontPickerFont, NexxtFontPickerInherit, NexxtFontPickerMessages, NexxtFontPickerProps, } from './components/organisms/FontPicker/FontPicker.vue';
44
+ export type { NexxtIconPickerCategory, NexxtIconPickerIcon, NexxtIconPickerMessages, NexxtIconPickerPinned, NexxtIconPickerProps, NexxtIconPickerStyle, NexxtIconPickerValue, } from './components/organisms/IconPicker/IconPicker.vue';
45
+ export { iconLabelFromName, iconSearchIndex, iconStyleFor, searchIcons, sortIconsByLabel, } from './components/organisms/IconPicker/iconPickerHelpers';
46
+ export type { NexxtIconPickerSearchEntry } from './components/organisms/IconPicker/iconPickerHelpers';
44
47
  export { EDITOR_PADDING_STEPS } from './components/editor/molecules/EditorPadding/EditorPadding.vue';
45
48
  export type { EditorPaddingMessages, EditorPaddingStep, } from './components/editor/molecules/EditorPadding/EditorPadding.vue';
46
49
  export { EDITOR_DIMENSION_LIMITS } from './components/editor/atoms/EditorDimensionField/EditorDimensionField.vue';
@@ -100,6 +103,7 @@ export { default as NexxtFloatingPanel } from './components/atoms/FloatingPanel/
100
103
  export { default as NexxtFontPicker } from './components/organisms/FontPicker/FontPicker.vue';
101
104
  export { default as NexxtHeader } from './components/organisms/Header/Header.vue';
102
105
  export { default as NexxtIcon } from './components/atoms/Icon/Icon.vue';
106
+ export { default as NexxtIconPicker } from './components/organisms/IconPicker/IconPicker.vue';
103
107
  export { default as NexxtInfoBlock } from './components/molecules/InfoBlock/InfoBlock.vue';
104
108
  export { default as NexxtInputField } from './components/molecules/InputField/InputField.vue';
105
109
  export { default as NexxtInputSelect } from './components/molecules/InputSelect/InputSelect.vue';