@unocss/autocomplete 0.29.1 → 0.29.4

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.
package/README.md CHANGED
@@ -33,7 +33,7 @@ rules: [
33
33
  The template uses a simle DSL to specify the autocomplete suggestions. The syntax is:
34
34
 
35
35
  - `(...|...)`: logic OR groups. `|` as the separator. Will be used as suggestions when the some of the groups match.
36
- - `<...>`: built-in short hands. currently supports `<num>`, `<precent>` and `<directions>`
36
+ - `<...>`: built-in short hands. currently supports `<num>`, `<percent>` and `<directions>`
37
37
  - `$...`: theme infering. for example, `$colors` will list all the properties of the `colors` object of the theme.
38
38
 
39
39
  For examples:
@@ -56,6 +56,18 @@ For examples:
56
56
  - **Input**: `text-r`
57
57
  - **Suggestions**: `text-red`, `text-rose` ...
58
58
 
59
+ ###### Example 4
60
+
61
+ For multiple templates
62
+
63
+ - **Template**: `['(border|b)-<num>', '(border|b)-<directions>-<num>']`
64
+
65
+ - **Input**: `b-`
66
+ - **Suggestions**: `b-x`, `b-y`, `b-1`, `b-2` ...
67
+
68
+ - **Input**: `b-x-`
69
+ - **Suggestions**: `b-x-1`, `b-x-2` ...
70
+
59
71
  ## License
60
72
 
61
73
  MIT License © 2021-PRESENT [Anthony Fu](https://github.com/antfu)
package/dist/index.cjs CHANGED
@@ -11,7 +11,7 @@ const LRU__default = /*#__PURE__*/_interopDefaultLegacy(LRU);
11
11
 
12
12
  const shorthands = {
13
13
  num: `(${[0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 24, 36].join("|")})`,
14
- precent: `(${[0, 25, 50, 45, 100].join("|")})`,
14
+ percent: `(${Array.from({ length: 11 }, (_, i) => i * 10).join("|")})`,
15
15
  directions: "(x|y|t|b|l|r|s|e)"
16
16
  };
17
17
  const ignoredThemeKeys = ["DEFAULT"];
@@ -41,10 +41,9 @@ function parseAutocomplete(template, theme = {}) {
41
41
  };
42
42
  function handleNonGroup(input) {
43
43
  handleRegexMatch(input, /\$([\w\|]+)/g, (m) => {
44
- const keys = m[1].split("|");
45
44
  parts.push({
46
45
  type: "theme",
47
- objects: keys.map((i) => {
46
+ objects: m[1].split("|").map((i) => {
48
47
  if (!i || !theme[i])
49
48
  throw new Error(`Invalid theme key ${i}`);
50
49
  return theme[i];
@@ -75,8 +74,14 @@ function parseAutocomplete(template, theme = {}) {
75
74
  while (tempParts.length) {
76
75
  const part = tempParts.shift();
77
76
  if (part.type === "static") {
78
- if (!rest.startsWith(part.value))
77
+ if (combinations.length)
78
+ combinations = combinations.map((i) => i + part.value);
79
+ if (part.value.startsWith(rest) && part.value !== rest && !combinations.length) {
80
+ combinations = [part.value];
79
81
  break;
82
+ } else if (!rest.startsWith(part.value)) {
83
+ break;
84
+ }
80
85
  matched += part.value;
81
86
  rest = rest.slice(part.value.length);
82
87
  } else if (part.type === "group") {
@@ -86,7 +91,8 @@ function parseAutocomplete(template, theme = {}) {
86
91
  rest = rest.slice(fullMatched.length);
87
92
  } else {
88
93
  combinations = part.values.filter((i) => i.startsWith(rest));
89
- break;
94
+ if (tempParts[0]?.type !== "static")
95
+ break;
90
96
  }
91
97
  } else if (part.type === "theme") {
92
98
  const keys = part.objects.flatMap((i) => Object.keys(i)).filter((i) => i && !ignoredThemeKeys.includes(i) && i[0] !== "_");
@@ -106,12 +112,11 @@ function parseAutocomplete(template, theme = {}) {
106
112
  }
107
113
  } else {
108
114
  combinations = keys.filter((i) => i.startsWith(rest));
109
- break;
115
+ if (tempParts[0]?.type !== "static")
116
+ break;
110
117
  }
111
118
  }
112
119
  }
113
- if (!matched)
114
- return [];
115
120
  if (combinations.length === 0)
116
121
  combinations.push("");
117
122
  return combinations.map((i) => matched + i).filter((i) => i.length >= input.length);
@@ -122,7 +127,7 @@ function createAutocomplete(uno) {
122
127
  const templateCache = /* @__PURE__ */ new Map();
123
128
  const cache = new LRU__default({ max: 1e3 });
124
129
  let staticUtils = [];
125
- let templates = [];
130
+ const templates = [];
126
131
  reset();
127
132
  return {
128
133
  suggest,
@@ -140,11 +145,18 @@ function createAutocomplete(uno) {
140
145
  return [];
141
146
  if (cache.has(input))
142
147
  return cache.get(input);
148
+ const [, processed, , variants] = uno.matchVariants(input);
149
+ const idx = input.search(processed);
150
+ if (idx === -1)
151
+ return [];
152
+ const variantPrefix = input.slice(0, idx);
153
+ const variantPostfix = input.slice(idx + input.length);
143
154
  const result = processSuggestions(await Promise.all([
144
- suggestSelf(input),
145
- suggestStatic(input),
146
- ...suggestFromPreset(input)
147
- ]));
155
+ suggestSelf(processed),
156
+ suggestStatic(processed),
157
+ ...suggestFromPreset(processed),
158
+ ...suggestVariant(processed, variants)
159
+ ]), variantPrefix, variantPostfix);
148
160
  cache.set(input, result);
149
161
  return result;
150
162
  }
@@ -158,23 +170,24 @@ function createAutocomplete(uno) {
158
170
  function suggestFromPreset(input) {
159
171
  return templates.map((fn) => typeof fn === "function" ? fn(input) : getParsed(fn)(input)) || [];
160
172
  }
173
+ function suggestVariant(input, used) {
174
+ return uno.config.variants.filter((v) => v.autocomplete && (v.multiPass || !used.has(v))).flatMap((v) => core.toArray(v.autocomplete || [])).map((fn) => typeof fn === "function" ? fn(input) : getParsed(fn)(input));
175
+ }
161
176
  function reset() {
162
177
  templateCache.clear();
163
178
  cache.clear();
164
179
  staticUtils = Object.keys(uno.config.rulesStaticMap);
165
- templates = [
166
- ...uno.config.autocomplete || [],
167
- ...uno.config.rulesDynamic.flatMap((i) => core.toArray(i?.[2]?.autocomplete || []))
168
- ];
180
+ templates.length = 0;
181
+ templates.push(...uno.config.autocomplete || [], ...uno.config.rulesDynamic.flatMap((i) => core.toArray(i?.[2]?.autocomplete || [])));
169
182
  }
170
- function processSuggestions(suggestions) {
171
- return core.uniq(suggestions.flat()).filter((i) => !!(i && !i.match(/[:-]$/))).sort((a, b) => {
183
+ function processSuggestions(suggestions, prefix = "", suffix = "") {
184
+ return core.uniq(suggestions.flat()).filter((i) => !!(i && !i.match(/-$/))).sort((a, b) => {
172
185
  const numA = +(a.match(/\d+$/)?.[0] || NaN);
173
186
  const numB = +(b.match(/\d+$/)?.[0] || NaN);
174
187
  if (!Number.isNaN(numA) && !Number.isNaN(numB))
175
188
  return numA - numB;
176
189
  return a.localeCompare(b);
177
- });
190
+ }).map((i) => prefix + i + suffix);
178
191
  }
179
192
  }
180
193
 
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { uniq, toArray } from '@unocss/core';
1
+ import { toArray, uniq } from '@unocss/core';
2
2
  import LRU from 'lru-cache';
3
3
 
4
4
  const shorthands = {
5
5
  num: `(${[0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 24, 36].join("|")})`,
6
- precent: `(${[0, 25, 50, 45, 100].join("|")})`,
6
+ percent: `(${Array.from({ length: 11 }, (_, i) => i * 10).join("|")})`,
7
7
  directions: "(x|y|t|b|l|r|s|e)"
8
8
  };
9
9
  const ignoredThemeKeys = ["DEFAULT"];
@@ -33,10 +33,9 @@ function parseAutocomplete(template, theme = {}) {
33
33
  };
34
34
  function handleNonGroup(input) {
35
35
  handleRegexMatch(input, /\$([\w\|]+)/g, (m) => {
36
- const keys = m[1].split("|");
37
36
  parts.push({
38
37
  type: "theme",
39
- objects: keys.map((i) => {
38
+ objects: m[1].split("|").map((i) => {
40
39
  if (!i || !theme[i])
41
40
  throw new Error(`Invalid theme key ${i}`);
42
41
  return theme[i];
@@ -67,8 +66,14 @@ function parseAutocomplete(template, theme = {}) {
67
66
  while (tempParts.length) {
68
67
  const part = tempParts.shift();
69
68
  if (part.type === "static") {
70
- if (!rest.startsWith(part.value))
69
+ if (combinations.length)
70
+ combinations = combinations.map((i) => i + part.value);
71
+ if (part.value.startsWith(rest) && part.value !== rest && !combinations.length) {
72
+ combinations = [part.value];
71
73
  break;
74
+ } else if (!rest.startsWith(part.value)) {
75
+ break;
76
+ }
72
77
  matched += part.value;
73
78
  rest = rest.slice(part.value.length);
74
79
  } else if (part.type === "group") {
@@ -78,7 +83,8 @@ function parseAutocomplete(template, theme = {}) {
78
83
  rest = rest.slice(fullMatched.length);
79
84
  } else {
80
85
  combinations = part.values.filter((i) => i.startsWith(rest));
81
- break;
86
+ if (tempParts[0]?.type !== "static")
87
+ break;
82
88
  }
83
89
  } else if (part.type === "theme") {
84
90
  const keys = part.objects.flatMap((i) => Object.keys(i)).filter((i) => i && !ignoredThemeKeys.includes(i) && i[0] !== "_");
@@ -98,12 +104,11 @@ function parseAutocomplete(template, theme = {}) {
98
104
  }
99
105
  } else {
100
106
  combinations = keys.filter((i) => i.startsWith(rest));
101
- break;
107
+ if (tempParts[0]?.type !== "static")
108
+ break;
102
109
  }
103
110
  }
104
111
  }
105
- if (!matched)
106
- return [];
107
112
  if (combinations.length === 0)
108
113
  combinations.push("");
109
114
  return combinations.map((i) => matched + i).filter((i) => i.length >= input.length);
@@ -114,7 +119,7 @@ function createAutocomplete(uno) {
114
119
  const templateCache = /* @__PURE__ */ new Map();
115
120
  const cache = new LRU({ max: 1e3 });
116
121
  let staticUtils = [];
117
- let templates = [];
122
+ const templates = [];
118
123
  reset();
119
124
  return {
120
125
  suggest,
@@ -132,11 +137,18 @@ function createAutocomplete(uno) {
132
137
  return [];
133
138
  if (cache.has(input))
134
139
  return cache.get(input);
140
+ const [, processed, , variants] = uno.matchVariants(input);
141
+ const idx = input.search(processed);
142
+ if (idx === -1)
143
+ return [];
144
+ const variantPrefix = input.slice(0, idx);
145
+ const variantPostfix = input.slice(idx + input.length);
135
146
  const result = processSuggestions(await Promise.all([
136
- suggestSelf(input),
137
- suggestStatic(input),
138
- ...suggestFromPreset(input)
139
- ]));
147
+ suggestSelf(processed),
148
+ suggestStatic(processed),
149
+ ...suggestFromPreset(processed),
150
+ ...suggestVariant(processed, variants)
151
+ ]), variantPrefix, variantPostfix);
140
152
  cache.set(input, result);
141
153
  return result;
142
154
  }
@@ -150,23 +162,24 @@ function createAutocomplete(uno) {
150
162
  function suggestFromPreset(input) {
151
163
  return templates.map((fn) => typeof fn === "function" ? fn(input) : getParsed(fn)(input)) || [];
152
164
  }
165
+ function suggestVariant(input, used) {
166
+ return uno.config.variants.filter((v) => v.autocomplete && (v.multiPass || !used.has(v))).flatMap((v) => toArray(v.autocomplete || [])).map((fn) => typeof fn === "function" ? fn(input) : getParsed(fn)(input));
167
+ }
153
168
  function reset() {
154
169
  templateCache.clear();
155
170
  cache.clear();
156
171
  staticUtils = Object.keys(uno.config.rulesStaticMap);
157
- templates = [
158
- ...uno.config.autocomplete || [],
159
- ...uno.config.rulesDynamic.flatMap((i) => toArray(i?.[2]?.autocomplete || []))
160
- ];
172
+ templates.length = 0;
173
+ templates.push(...uno.config.autocomplete || [], ...uno.config.rulesDynamic.flatMap((i) => toArray(i?.[2]?.autocomplete || [])));
161
174
  }
162
- function processSuggestions(suggestions) {
163
- return uniq(suggestions.flat()).filter((i) => !!(i && !i.match(/[:-]$/))).sort((a, b) => {
175
+ function processSuggestions(suggestions, prefix = "", suffix = "") {
176
+ return uniq(suggestions.flat()).filter((i) => !!(i && !i.match(/-$/))).sort((a, b) => {
164
177
  const numA = +(a.match(/\d+$/)?.[0] || NaN);
165
178
  const numB = +(b.match(/\d+$/)?.[0] || NaN);
166
179
  if (!Number.isNaN(numA) && !Number.isNaN(numB))
167
180
  return numA - numB;
168
181
  return a.localeCompare(b);
169
- });
182
+ }).map((i) => prefix + i + suffix);
170
183
  }
171
184
  }
172
185
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unocss/autocomplete",
3
- "version": "0.29.1",
3
+ "version": "0.29.4",
4
4
  "description": "Autocomplete utils for UnoCSS",
5
5
  "keywords": [
6
6
  "unocss",
@@ -36,11 +36,11 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/lru-cache": "^7.4.0",
39
- "@unocss/core": "0.29.1"
39
+ "@unocss/core": "0.29.4"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "unbuild",
43
43
  "stub": "unbuild --stub"
44
44
  },
45
- "readme": "# @unocss/autocomplete\n\nAutocomplete utils for UnoCSS. This is embedded in [the playground](https://unocss.antfu.me/) and [the VS Code extension](https://github.com/unocss/unocss/tree/main/packages/vscode).\n\n## Syntax\n\nTo add autocomplete support to your custom rules:\n\n### Static Rules\n\nStatic rules like this will just works without any configuration.\n\n```ts\nrules: [\n ['flex', { display: 'flex' }]\n]\n```\n\n### Dynamic Rules\n\nFor dynamic rules, you can provide an extra `meta` object to the rule and specify the autocomplete template.\n\n```ts\nrules: [\n [\n /^m-(\\d)$/,\n ([, d]) => ({ margin: `${d / 4}rem` }),\n { autocomplete: 'm-<num>' }, // <-- this\n ],\n]\n```\n\nThe template uses a simle DSL to specify the autocomplete suggestions. The syntax is:\n\n- `(...|...)`: logic OR groups. `|` as the separator. Will be used as suggestions when the some of the groups match.\n- `<...>`: built-in short hands. currently supports `<num>`, `<precent>` and `<directions>`\n- `$...`: theme infering. for example, `$colors` will list all the properties of the `colors` object of the theme.\n\nFor examples:\n\n###### Example 1\n\n- **Template**: `(border|b)-(solid|dashed|dotted|double|hidden|none)`\n- **Input**: `b-do`\n- **Suggestions**: `b-dashed`, `b-double`\n\n###### Example 2\n\n- **Template**: `m-<num>`\n- **Input**: `m-`\n- **Suggestions**: `m-1`, `m-2`, `m-3` ...\n\n###### Example 3\n\n- **Template**: `text-$colors`\n- **Input**: `text-r`\n- **Suggestions**: `text-red`, `text-rose` ...\n\n## License\n\nMIT License © 2021-PRESENT [Anthony Fu](https://github.com/antfu)\n"
45
+ "readme": "# @unocss/autocomplete\n\nAutocomplete utils for UnoCSS. This is embedded in [the playground](https://unocss.antfu.me/) and [the VS Code extension](https://github.com/unocss/unocss/tree/main/packages/vscode).\n\n## Syntax\n\nTo add autocomplete support to your custom rules:\n\n### Static Rules\n\nStatic rules like this will just works without any configuration.\n\n```ts\nrules: [\n ['flex', { display: 'flex' }]\n]\n```\n\n### Dynamic Rules\n\nFor dynamic rules, you can provide an extra `meta` object to the rule and specify the autocomplete template.\n\n```ts\nrules: [\n [\n /^m-(\\d)$/,\n ([, d]) => ({ margin: `${d / 4}rem` }),\n { autocomplete: 'm-<num>' }, // <-- this\n ],\n]\n```\n\nThe template uses a simle DSL to specify the autocomplete suggestions. The syntax is:\n\n- `(...|...)`: logic OR groups. `|` as the separator. Will be used as suggestions when the some of the groups match.\n- `<...>`: built-in short hands. currently supports `<num>`, `<percent>` and `<directions>`\n- `$...`: theme infering. for example, `$colors` will list all the properties of the `colors` object of the theme.\n\nFor examples:\n\n###### Example 1\n\n- **Template**: `(border|b)-(solid|dashed|dotted|double|hidden|none)`\n- **Input**: `b-do`\n- **Suggestions**: `b-dashed`, `b-double`\n\n###### Example 2\n\n- **Template**: `m-<num>`\n- **Input**: `m-`\n- **Suggestions**: `m-1`, `m-2`, `m-3` ...\n\n###### Example 3\n\n- **Template**: `text-$colors`\n- **Input**: `text-r`\n- **Suggestions**: `text-red`, `text-rose` ...\n\n###### Example 4\n\nFor multiple templates\n\n- **Template**: `['(border|b)-<num>', '(border|b)-<directions>-<num>']`\n\n- **Input**: `b-`\n- **Suggestions**: `b-x`, `b-y`, `b-1`, `b-2` ...\n\n- **Input**: `b-x-`\n- **Suggestions**: `b-x-1`, `b-x-2` ...\n\n## License\n\nMIT License © 2021-PRESENT [Anthony Fu](https://github.com/antfu)\n"
46
46
  }