@gurpinderjitsingh/recipe-ui 0.12.0 → 0.13.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.
- package/dist/cjs/app-modal_7.cjs.entry.js +150 -47
- package/dist/cjs/app-toast.cjs.entry.js +1 -1
- package/dist/collection/components/app-toast/app-toast.js +1 -1
- package/dist/collection/components/recipe-card/recipe-card.js +1 -1
- package/dist/collection/components/recipe-filter-bar/recipe-filter-bar.js +1 -1
- package/dist/collection/components/recipe-form/recipe-form.css +4 -0
- package/dist/collection/components/recipe-form/recipe-form.js +144 -41
- package/dist/collection/components/recipe-rating/recipe-rating.js +1 -1
- package/dist/collection/components/recipe-search-bar/recipe-search-bar.js +2 -2
- package/dist/components/app-toast.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/p-2Oa3Ks4e.js +1 -0
- package/dist/components/{p-DElrp5qn.js → p-BWjrK8cx.js} +1 -1
- package/dist/components/{p-BBMv9wjr.js → p-BjJGcNvA.js} +1 -1
- package/dist/components/p-DPXKwfGM.js +1 -0
- package/dist/components/{p-B_OSW9IJ.js → p-HEDJ6pyO.js} +1 -1
- package/dist/components/{p-CayP90fv.js → p-ltkIKdRy.js} +1 -1
- package/dist/components/recipe-card.js +1 -1
- package/dist/components/recipe-filter-bar.js +1 -1
- package/dist/components/recipe-form.js +1 -1
- package/dist/components/recipe-rating.js +1 -1
- package/dist/components/recipe-search-bar.js +1 -1
- package/dist/esm/app-modal_7.entry.js +150 -47
- package/dist/esm/app-toast.entry.js +1 -1
- package/dist/recipe-ui/p-7e9d3224.entry.js +1 -0
- package/dist/recipe-ui/p-dca78e59.entry.js +1 -0
- package/dist/recipe-ui/recipe-ui.esm.js +1 -1
- package/dist/types/components/recipe-form/recipe-form.d.ts +15 -3
- package/package.json +1 -1
- package/dist/components/p-8ogxleRP.js +0 -1
- package/dist/components/p-CcOtmzb-.js +0 -1
- package/dist/recipe-ui/p-13f32fd3.entry.js +0 -1
- package/dist/recipe-ui/p-9c0be643.entry.js +0 -1
|
@@ -21,7 +21,7 @@ const RecipeCard = class {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
render() {
|
|
24
|
-
return (index.h("div", { key: '
|
|
24
|
+
return (index.h("div", { key: '57023f5420716527cf5bb0a6f775bb62a19f70b6', class: "card", onClick: () => this.cardClick.emit() }, index.h("div", { key: '137fab4bde9ee40e26217280ba5736b51b96767f', class: "image-wrap" }, this.image ? index.h("img", { src: this.image, alt: this.recipeTitle }) : index.h("div", { class: "placeholder" }), index.h("button", { key: '99b992c4c50082ec42c4b9473b8418d11fe02e10', class: { 'fav-btn': true, active: this.favorite }, onClick: this.onFavoriteClick, "aria-label": "Toggle favorite" }, this.favorite ? '★' : '☆')), index.h("div", { key: '34a0670cb5e1716e6d7b17d4b1ad3aa5e19b614f', class: "body" }, index.h("h3", { key: 'c2f5ed25dc9435c10a0b476cebf10e2a7fcfcbd4' }, this.recipeTitle), index.h("span", { key: 'e4ee0142c7290110c4cb61bd9a3cae4f2503ca69', class: "types" }, this.category && index.h("span", { key: '0faf05e5d79a532dd5947f4f51fc44ca75f51844', class: "category" }, this.category), this.cuisine && index.h("span", { key: 'e8aee0b08bed65c359fc589412d89a14ed81f091', class: "cuisine" }, this.cuisine)), index.h("div", { key: '7c000476afc7687f4318abf6df26ba83bac131e2', class: "actions" }, index.h("slot", { key: 'e613619696cb0f3967426e1dbb245d23a8913d3d', name: "actions" })))));
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
RecipeCard.style = recipeCardCss();
|
|
@@ -58,8 +58,8 @@ const RecipeSearchBar = class {
|
|
|
58
58
|
this.internalValue = newVal;
|
|
59
59
|
}
|
|
60
60
|
render() {
|
|
61
|
-
return (index.h("div", { key: '
|
|
62
|
-
index.h("button", { key: '
|
|
61
|
+
return (index.h("div", { key: 'd4be8af300e73f7a6526ec48993db0259aafcbe2', class: "wrap" }, index.h("input", { key: '896908d0b0e10212eae53284d7a6fad79f34c5de', type: "search", placeholder: this.placeholder, value: this.internalValue, onInput: this.onInput, onKeyDown: this.onKeyDown }), this.showSearchButton &&
|
|
62
|
+
index.h("button", { key: '963394555e1febf733b50153e82858077021800c', onClick: () => this.search.emit({ value: this.internalValue }), "aria-label": "Search" }, "\uD83D\uDD0D")));
|
|
63
63
|
}
|
|
64
64
|
static get watchers() { return {
|
|
65
65
|
"value": [{
|
|
@@ -83,7 +83,7 @@ const RecipeFilterBar = class {
|
|
|
83
83
|
}
|
|
84
84
|
render() {
|
|
85
85
|
const cats = Array.isArray(this.categories) ? this.categories : [];
|
|
86
|
-
return (index.h("div", { key: '
|
|
86
|
+
return (index.h("div", { key: 'c19ffd90b0eff5c4b9b06602c9432b1210cc27f7', class: "wrap" }, index.h("button", { key: '3a629b0e211a6b9ab80b015da2d4be44c85f59a1', class: { chip: true, active: this.active === '' }, onClick: () => this.select('') }, "All"), cats.map((c) => (index.h("button", { class: { chip: true, active: this.active === c }, onClick: () => this.select(c) }, c)))));
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
89
|
RecipeFilterBar.style = recipeFilterBarCss();
|
|
@@ -100,12 +100,12 @@ const RecipeRating = class {
|
|
|
100
100
|
}
|
|
101
101
|
render() {
|
|
102
102
|
const stars = Array.from({ length: this.max }, (_, i) => i + 1);
|
|
103
|
-
return (index.h("div", { key: '
|
|
103
|
+
return (index.h("div", { key: '47d3b89bf17f95c679f7931ee61d7eea4fc5c556', class: "wrap", role: this.readonly ? undefined : 'radiogroup' }, stars.map((s) => (index.h("span", { class: { star: true, filled: s <= this.value, clickable: !this.readonly }, onClick: () => !this.readonly && this.ratingChange.emit({ value: s }) }, "\u2605")))));
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
106
|
RecipeRating.style = recipeRatingCss();
|
|
107
107
|
|
|
108
|
-
const recipeFormCss = () => `:host{display:block;font-family:system-ui, sans-serif}form{display:flex;flex-direction:column;gap:14px}label{display:flex;flex-direction:column;gap:4px;font-size:13px;color:#333;font-weight:600}input,textarea,select{font-weight:400;padding:8px 10px;border:1px solid #ddd;border-radius:6px;font-size:14px;font-family:inherit;background:#fff;transition:border-color 0.15s ease, box-shadow 0.15s ease}input:focus,textarea:focus,select:focus{outline:none;border-color:rgb(235, 98, 48);box-shadow:0 0 0 3px rgba(255, 107, 53, 0.14)}select{appearance:none;-webkit-appearance:none;-moz-appearance:none;padding-right:34px;cursor:pointer;color:#1f2937;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;background-size:14px}select:hover{border-color:#bbb}select:invalid,select option[value=""]{color:#9ca3af}.row{display:grid;grid-template-columns:1fr 1fr;gap:14px}@media (max-width: 480px){.row{grid-template-columns:1fr}}.field{display:flex;flex-direction:column;gap:6px;font-size:13px;font-weight:600}.ingredient-row{display:flex;gap:6px}.ingredient-row input{flex:1}.ingredient-row button{border:none;background:#f4f4f4;border-radius:6px;cursor:pointer;width:30px}.add-btn{align-self:flex-start;border:1px dashed #bbb;background:none;border-radius:6px;padding:6px 10px;cursor:pointer;font-size:13px;color:#555}.error{color:#e74c3c;font-size:12px;font-weight:400}.footer{display:flex;justify-content:flex-end;gap:10px;margin-top:6px}.cancel-btn{border:1px solid #ddd;background:#fff;border-radius:8px;padding:8px 16px;cursor:pointer}.save-btn{border:none;background:#ff6b35;color:#fff;border-radius:8px;padding:8px 18px;cursor:pointer;font-weight:600}`;
|
|
108
|
+
const recipeFormCss = () => `:host{display:block;font-family:system-ui, sans-serif}form{display:flex;flex-direction:column;gap:14px}label{display:flex;flex-direction:column;gap:4px;font-size:13px;color:#333;font-weight:600}input,textarea,select{font-weight:400;padding:8px 10px;border:1px solid #ddd;border-radius:6px;font-size:14px;font-family:inherit;background:#fff;transition:border-color 0.15s ease, box-shadow 0.15s ease}input:focus,textarea:focus,select:focus{outline:none;border-color:rgb(235, 98, 48);box-shadow:0 0 0 3px rgba(255, 107, 53, 0.14)}select{appearance:none;-webkit-appearance:none;-moz-appearance:none;padding-right:34px;cursor:pointer;color:#1f2937;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;background-size:14px}select:hover{border-color:#bbb}select:invalid,select option[value=""]{color:#9ca3af}.row{display:grid;grid-template-columns:1fr 1fr;gap:14px}@media (max-width: 480px){.row{grid-template-columns:1fr}}.field{display:flex;flex-direction:column;gap:6px;font-size:13px;font-weight:600}.ingredient-row{display:flex;gap:6px}.ingredient-row input{flex:1}.ingredient-row button{border:none;background:#f4f4f4;border-radius:6px;cursor:pointer;width:30px}.add-btn{align-self:flex-start;border:1px dashed #bbb;background:none;border-radius:6px;padding:6px 10px;cursor:pointer;font-size:13px;color:#555}.error{color:#e74c3c;font-size:12px;font-weight:400}.footer{display:flex;justify-content:flex-end;gap:10px;margin-top:6px}.cancel-btn{border:1px solid #ddd;background:#fff;border-radius:8px;padding:8px 16px;cursor:pointer}.save-btn{border:none;background:#ff6b35;color:#fff;border-radius:8px;padding:8px 18px;cursor:pointer;font-weight:600}.required{color:red}`;
|
|
109
109
|
|
|
110
110
|
const DEFAULT_CATEGORIES = [
|
|
111
111
|
'Beef', 'Breakfast', 'Chicken', 'Dessert', 'Goat', 'Lamb',
|
|
@@ -119,6 +119,14 @@ const DEFAULT_AREAS = [
|
|
|
119
119
|
'Portuguese', 'Russian', 'Spanish', 'Thai', 'Tunisian', 'Turkish',
|
|
120
120
|
'Vietnamese', 'Other',
|
|
121
121
|
];
|
|
122
|
+
const LIMITS = {
|
|
123
|
+
title: { min: 5, max: 100 },
|
|
124
|
+
instructions: { min: 20, max: 5000 },
|
|
125
|
+
ingredient: { min: 5, max: 200 },
|
|
126
|
+
customCategory: { min: 5, max: 40 },
|
|
127
|
+
customArea: { min: 5, max: 40 },
|
|
128
|
+
image: { max: 500 },
|
|
129
|
+
};
|
|
122
130
|
const RecipeForm = class {
|
|
123
131
|
constructor(hostRef) {
|
|
124
132
|
index.registerInstance(this, hostRef);
|
|
@@ -158,10 +166,9 @@ const RecipeForm = class {
|
|
|
158
166
|
this.ingredients = [...this.ingredients, ''];
|
|
159
167
|
};
|
|
160
168
|
this.removeIngredient = (index) => {
|
|
161
|
-
this.ingredients = this.ingredients.filter((_, i) => i !== index);
|
|
162
169
|
const next = this.ingredients.filter((_, i) => i !== index);
|
|
163
170
|
this.ingredients = next;
|
|
164
|
-
this.
|
|
171
|
+
this.setFieldError('ingredients', this.validateIngredients(next));
|
|
165
172
|
};
|
|
166
173
|
}
|
|
167
174
|
componentWillLoad() {
|
|
@@ -186,10 +193,83 @@ const RecipeForm = class {
|
|
|
186
193
|
get fullAreaList() {
|
|
187
194
|
return this.mergeList(this.areas, this.extraAreas);
|
|
188
195
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
// ---- Per-field validators. Each returns an error message, or null when
|
|
197
|
+
// the value is valid. Used both by validate() on submit AND live on every
|
|
198
|
+
// keystroke, so the two can never drift out of sync with each other. ----
|
|
199
|
+
validateTitle(value) {
|
|
200
|
+
const len = value.trim().length;
|
|
201
|
+
if (len === 0)
|
|
202
|
+
return 'Title is required.';
|
|
203
|
+
if (len < LIMITS.title.min)
|
|
204
|
+
return `Title must be at least ${LIMITS.title.min} characters.`;
|
|
205
|
+
if (len > LIMITS.title.max)
|
|
206
|
+
return `Title must be ${LIMITS.title.max} characters or fewer.`;
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
validateImage(value) {
|
|
210
|
+
if (value.trim().length > LIMITS.image.max) {
|
|
211
|
+
return `Image URL must be ${LIMITS.image.max} characters or fewer.`;
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
validateIngredients(list) {
|
|
216
|
+
const clean = list.map((i) => i.trim()).filter(Boolean);
|
|
217
|
+
if (clean.length === 0)
|
|
218
|
+
return 'Add at least one ingredient.';
|
|
219
|
+
if (clean.some((i) => i.length < LIMITS.ingredient.min)) {
|
|
220
|
+
return `Each ingredient must be at least ${LIMITS.ingredient.min} characters.`;
|
|
221
|
+
}
|
|
222
|
+
if (clean.some((i) => i.length > LIMITS.ingredient.max)) {
|
|
223
|
+
return `Each ingredient must be ${LIMITS.ingredient.max} characters or fewer.`;
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
validateInstructions(value) {
|
|
228
|
+
const len = value.trim().length;
|
|
229
|
+
if (len === 0)
|
|
230
|
+
return 'Instructions are required.';
|
|
231
|
+
if (len < LIMITS.instructions.min) {
|
|
232
|
+
return `Instructions must be at least ${LIMITS.instructions.min} characters — add a bit more detail.`;
|
|
233
|
+
}
|
|
234
|
+
if (len > LIMITS.instructions.max)
|
|
235
|
+
return `Instructions must be ${LIMITS.instructions.max} characters or fewer.`;
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
validateCategory(value) {
|
|
239
|
+
return value.trim() ? null : 'Category is required.';
|
|
240
|
+
}
|
|
241
|
+
validateCustomCategory(value) {
|
|
242
|
+
const len = value.trim().length;
|
|
243
|
+
if (len === 0)
|
|
244
|
+
return 'Enter a category name.';
|
|
245
|
+
if (len < LIMITS.customCategory.min || len > LIMITS.customCategory.max) {
|
|
246
|
+
return `Category name must be ${LIMITS.customCategory.min}-${LIMITS.customCategory.max} characters.`;
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
validateArea(value) {
|
|
251
|
+
return value.trim() ? null : 'Cuisine / Area is required.';
|
|
252
|
+
}
|
|
253
|
+
validateCustomArea(value) {
|
|
254
|
+
const len = value.trim().length;
|
|
255
|
+
if (len === 0)
|
|
256
|
+
return 'Enter a cuisine name.';
|
|
257
|
+
if (len < LIMITS.customArea.min || len > LIMITS.customArea.max) {
|
|
258
|
+
return `Cuisine name must be ${LIMITS.customArea.min}-${LIMITS.customArea.max} characters.`;
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
/** Sets or clears a single field's error live — the core of "show error
|
|
263
|
+
* if any, else clear" behavior. Only touches `errors` when the message
|
|
264
|
+
* actually changed, to avoid redundant re-renders on every keystroke. */
|
|
265
|
+
setFieldError(key, message) {
|
|
266
|
+
const current = this.errors[key] ?? null;
|
|
267
|
+
if (current === message)
|
|
268
|
+
return;
|
|
269
|
+
if (message) {
|
|
270
|
+
this.errors = { ...this.errors, [key]: message };
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
193
273
|
const next = { ...this.errors };
|
|
194
274
|
delete next[key];
|
|
195
275
|
this.errors = next;
|
|
@@ -231,28 +311,45 @@ const RecipeForm = class {
|
|
|
231
311
|
this.area = data.cuisine ?? '';
|
|
232
312
|
this.customArea = '';
|
|
233
313
|
}
|
|
314
|
+
// Reset any stale errors when the form is (re)populated, e.g. when
|
|
315
|
+
// switching from "new recipe" to editing an existing one.
|
|
316
|
+
this.errors = {};
|
|
234
317
|
}
|
|
235
318
|
}
|
|
319
|
+
/** Full validation pass, run on submit. Reuses the same per-field
|
|
320
|
+
* validators as live typing, so submit can never disagree with what
|
|
321
|
+
* the user already saw on screen. */
|
|
236
322
|
validate() {
|
|
237
323
|
const errors = {};
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
errors.
|
|
324
|
+
const titleErr = this.validateTitle(this.title);
|
|
325
|
+
if (titleErr)
|
|
326
|
+
errors.title = titleErr;
|
|
327
|
+
const imageErr = this.validateImage(this.image);
|
|
328
|
+
if (imageErr)
|
|
329
|
+
errors.image = imageErr;
|
|
330
|
+
const ingredientsErr = this.validateIngredients(this.ingredients);
|
|
331
|
+
if (ingredientsErr)
|
|
332
|
+
errors.ingredients = ingredientsErr;
|
|
333
|
+
const instructionsErr = this.validateInstructions(this.instructions);
|
|
334
|
+
if (instructionsErr)
|
|
335
|
+
errors.instructions = instructionsErr;
|
|
336
|
+
const categoryErr = this.validateCategory(this.category);
|
|
337
|
+
if (categoryErr) {
|
|
338
|
+
errors.category = categoryErr;
|
|
247
339
|
}
|
|
248
|
-
else if (this.category === 'Other'
|
|
249
|
-
|
|
340
|
+
else if (this.category === 'Other') {
|
|
341
|
+
const customCategoryErr = this.validateCustomCategory(this.customCategory);
|
|
342
|
+
if (customCategoryErr)
|
|
343
|
+
errors.customCategory = customCategoryErr;
|
|
250
344
|
}
|
|
251
|
-
|
|
252
|
-
|
|
345
|
+
const areaErr = this.validateArea(this.area);
|
|
346
|
+
if (areaErr) {
|
|
347
|
+
errors.area = areaErr;
|
|
253
348
|
}
|
|
254
|
-
else if (this.area === 'Other'
|
|
255
|
-
|
|
349
|
+
else if (this.area === 'Other') {
|
|
350
|
+
const customAreaErr = this.validateCustomArea(this.customArea);
|
|
351
|
+
if (customAreaErr)
|
|
352
|
+
errors.customArea = customAreaErr;
|
|
256
353
|
}
|
|
257
354
|
this.errors = errors;
|
|
258
355
|
return Object.keys(errors).length === 0;
|
|
@@ -261,33 +358,39 @@ const RecipeForm = class {
|
|
|
261
358
|
const next = [...this.ingredients];
|
|
262
359
|
next[index] = value;
|
|
263
360
|
this.ingredients = next;
|
|
264
|
-
this.
|
|
361
|
+
this.setFieldError('ingredients', this.validateIngredients(next));
|
|
265
362
|
}
|
|
266
363
|
render() {
|
|
267
|
-
return (index.h("form", { key: '
|
|
268
|
-
|
|
269
|
-
this.
|
|
270
|
-
} }),
|
|
271
|
-
|
|
272
|
-
this.
|
|
364
|
+
return (index.h("form", { key: 'f562e5fa4cdd1f49b6b119471bf7773e319423e8', onSubmit: this.onSubmit }, index.h("slot", { key: '0bcfd3c288244952e69b1206449d6046ff9f832b', name: "header" }), index.h("label", { key: 'b94ca99a985de9ab0a4a827854c6e9f3c2c32228' }, index.h("span", { key: 'ea3f3a53edb24ec2a8421c2b97fee17877fa507a' }, "Title ", index.h("span", { key: 'ef3093980bc013d65787ae4a0e04c5a86564433e', class: "required" }, "*")), index.h("input", { key: 'f9748efc0027f3783d2961d11524c59ca58121fe', type: "text", maxLength: LIMITS.title.max, value: this.title, onInput: (e) => {
|
|
365
|
+
this.title = e.target.value;
|
|
366
|
+
this.setFieldError('title', this.validateTitle(this.title));
|
|
367
|
+
} }), index.h("span", { key: '0ac83523c019253560b219137390b8fdd3626323', class: "char-count" }, this.title.trim().length, "/", LIMITS.title.max), this.errors.title && index.h("span", { key: '2f1a55d2aa593182c3fe6330b3248985331aca2e', class: "error" }, this.errors.title)), index.h("label", { key: 'aa7d01fd11b9b4ea0551e8a157a70a666b645720' }, "Image URL", index.h("input", { key: 'fd26aabc19167c469419a1714358615f62b125b9', type: "text", maxLength: LIMITS.image.max, value: this.image, onInput: (e) => {
|
|
368
|
+
this.image = e.target.value;
|
|
369
|
+
this.setFieldError('image', this.validateImage(this.image));
|
|
370
|
+
} }), this.errors.image && index.h("span", { key: '3f9561c7ee8433cee875c638edcb069baef96b86', class: "error" }, this.errors.image)), index.h("div", { key: '4253c71219c77f40ef8ec811700fa2ffb4e23d55', class: "row" }, index.h("label", { key: '7b892f3e2e87d7ab647050859996f7fcccbec42c' }, index.h("span", { key: '3f63f3f57f9df8673b54c42251282918fee1be69' }, "Category ", index.h("span", { key: 'd535dbd85bc96e1af88511f903d96046f23cb283', class: "required" }, "*")), index.h("select", { key: '311099318b5b7e6212eae0c9803adcf2437aa024', onInput: (e) => {
|
|
371
|
+
this.category = e.target.value;
|
|
372
|
+
this.setFieldError('category', this.validateCategory(this.category));
|
|
273
373
|
if (this.category !== 'Other')
|
|
274
|
-
this.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
374
|
+
this.setFieldError('customCategory', null);
|
|
375
|
+
else
|
|
376
|
+
this.setFieldError('customCategory', this.validateCustomCategory(this.customCategory));
|
|
377
|
+
} }, index.h("option", { key: '9ab9ed037d1cabc6829cf35bf8c77d5ae8ff6518', value: "", selected: this.category === '' }, "Select a category\u2026"), this.fullCategoryList.map((c) => (index.h("option", { value: c, selected: c === this.category }, c)))), this.errors.category && index.h("span", { key: '48a10209ff1b6425220388ba0f315899947bb37a', class: "error" }, this.errors.category)), index.h("label", { key: '294923e0daebc5aa126e66c6e8319ca087544dc4' }, index.h("span", { key: 'e9fc761f634c20cfc02829fcfeb4767dfaf4c69f' }, "Cuisine / Area ", index.h("span", { key: '52254653a745ef5459e7efd55d688e37324d358e', class: "required" }, "*")), index.h("select", { key: '7938a0a5b0bb6004b29578aee87cf5711e1d935d', onInput: (e) => {
|
|
378
|
+
this.area = e.target.value;
|
|
379
|
+
this.setFieldError('area', this.validateArea(this.area));
|
|
278
380
|
if (this.area !== 'Other')
|
|
279
|
-
this.
|
|
280
|
-
|
|
281
|
-
|
|
381
|
+
this.setFieldError('customArea', null);
|
|
382
|
+
else
|
|
383
|
+
this.setFieldError('customArea', this.validateCustomArea(this.customArea));
|
|
384
|
+
} }, index.h("option", { key: '2e3a43ac518d6d6662cda3c269055cac2d142cd0', value: "", selected: this.area === '' }, "Select a cuisine\u2026"), this.fullAreaList.map((a) => (index.h("option", { value: a, selected: a === this.area }, a)))), this.errors.area && index.h("span", { key: '9776cc4829e490a06c34ba6e6d8482fbda1499af', class: "error" }, this.errors.area))), (this.category === 'Other' || this.area === 'Other') && (index.h("div", { key: 'edf7709c6bb1fdf2d11d360dd4bff73067ace685', class: "row" }, this.category === 'Other' && (index.h("label", { key: 'e1b54a1298d4d9b7f2db16be20095c229fd7d72b', class: "custom-area-field" }, "Enter category name", index.h("input", { key: 'e538a1f8da6e55875d7b37538a205bfe09c7e48a', type: "text", placeholder: "e.g. Brunch", maxLength: LIMITS.customCategory.max, value: this.customCategory, onInput: (e) => {
|
|
282
385
|
this.customCategory = e.target.value;
|
|
283
|
-
this.
|
|
284
|
-
} }), this.errors.customCategory && index.h("span", { key: '
|
|
386
|
+
this.setFieldError('customCategory', this.validateCustomCategory(this.customCategory));
|
|
387
|
+
} }), this.errors.customCategory && index.h("span", { key: 'd76519fb39dbc17512c63f8923587219c6f126d1', class: "error" }, this.errors.customCategory))), this.area === 'Other' && (index.h("label", { key: '0b46c004deda4af6a71a503f950f990d340850f8', class: "custom-area-field" }, "Enter cuisine name", index.h("input", { key: '3f312b2aaa6b0345ac476a0aa7919ce5638f0205', type: "text", placeholder: "e.g. Ethiopian", maxLength: LIMITS.customArea.max, value: this.customArea, onInput: (e) => {
|
|
285
388
|
this.customArea = e.target.value;
|
|
286
|
-
this.
|
|
287
|
-
} }), this.errors.customArea && index.h("span", { key: '
|
|
389
|
+
this.setFieldError('customArea', this.validateCustomArea(this.customArea));
|
|
390
|
+
} }), this.errors.customArea && index.h("span", { key: 'a7d0487409a2f2338fd32ce23770da1fff318189', class: "error" }, this.errors.customArea))))), index.h("div", { key: '2af4f405001d202a86c0e94426db89b46d4af0c5', class: "field" }, index.h("span", { key: '1cc25f9cacb59981f1c8b6faf5c7669693454d86' }, "Ingredients ", index.h("span", { key: '12463cc84c7df68329044f6e00bbf489dc02efbc', class: "required" }, "*")), this.ingredients.map((ing, i) => (index.h("div", { class: "ingredient-row" }, index.h("input", { type: "text", maxLength: LIMITS.ingredient.max, value: ing, onInput: (e) => this.updateIngredient(i, e.target.value) }), index.h("button", { type: "button", onClick: () => this.removeIngredient(i), "aria-label": "Remove" }, "\u2715")))), index.h("button", { key: 'faadffd1444fa729327bb44e2ba430a38fb8d0f2', type: "button", class: "add-btn", onClick: this.addIngredient }, "+ Add ingredient"), this.errors.ingredients && index.h("span", { key: '93e3101aa6f8aa6adb28a5cb121cc2f735bdf3cb', class: "error" }, this.errors.ingredients)), index.h("label", { key: '142d68b899f6264366351ff0edefac0755f5c021' }, index.h("span", { key: 'd0469328a9f808854e2bc1daeb2df3a2562300e1' }, "Instructions ", index.h("span", { key: 'df0b49c132848b889adc1a070a17d90505f51f9b', class: "required" }, "*"), " "), index.h("textarea", { key: '790e5cb9c24947648df27697c7148636e2862bd5', rows: 5, maxLength: LIMITS.instructions.max, onInput: (e) => {
|
|
288
391
|
this.instructions = e.target.value;
|
|
289
|
-
this.
|
|
290
|
-
} }, this.instructions), this.errors.instructions && index.h("span", { key: '
|
|
392
|
+
this.setFieldError('instructions', this.validateInstructions(this.instructions));
|
|
393
|
+
} }, this.instructions), index.h("span", { key: 'ae15de2b6a210955334f16fcc0040a739bf62f31', class: "char-count" }, this.instructions.trim().length, "/", LIMITS.instructions.max), this.errors.instructions && index.h("span", { key: 'db148c0b5347d6a899adb4daf18a59ea19221e7f', class: "error" }, this.errors.instructions)), index.h("div", { key: 'b42405e2778e862115d5841843a4e63bf5ad5e7a', class: "footer" }, index.h("slot", { key: 'c4a8533636d1dd5fac2b391e36314569f05a4d01', name: "footer" }), index.h("button", { key: '4ea910ae3983fcdb133dbdc38ad122b607eb3d5c', type: "button", class: "cancel-btn", onClick: () => this.cancel.emit() }, "Cancel"), index.h("button", { key: 'a2ea39907bba8f4c35b8f2eaaa501f31bdf17130', type: "submit", class: "save-btn" }, "Save Recipe"))));
|
|
291
394
|
}
|
|
292
395
|
static get watchers() { return {
|
|
293
396
|
"initialData": [{
|
|
@@ -18,7 +18,7 @@ const AppToast = class {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
render() {
|
|
21
|
-
return (index.h("div", { key: '
|
|
21
|
+
return (index.h("div", { key: '6d17f8582228f7ec27219c9a9a39d5bd76a780dd', class: `toast ${this.type}` }, index.h("span", { key: 'c0524ae830e6c3bdd73f1e0561caaf5a4ae73468' }, this.message), index.h("button", { key: '7aab76915df455b48d2ca6a5d9e0985f7bb87907', onClick: () => this.dismiss.emit(), "aria-label": "Dismiss" }, "\u2715")));
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
AppToast.style = appToastCss();
|
|
@@ -12,7 +12,7 @@ export class AppToast {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
render() {
|
|
15
|
-
return (h("div", { key: '
|
|
15
|
+
return (h("div", { key: '6d17f8582228f7ec27219c9a9a39d5bd76a780dd', class: `toast ${this.type}` }, h("span", { key: 'c0524ae830e6c3bdd73f1e0561caaf5a4ae73468' }, this.message), h("button", { key: '7aab76915df455b48d2ca6a5d9e0985f7bb87907', onClick: () => this.dismiss.emit(), "aria-label": "Dismiss" }, "\u2715")));
|
|
16
16
|
}
|
|
17
17
|
static get is() { return "app-toast"; }
|
|
18
18
|
static get encapsulation() { return "shadow"; }
|
|
@@ -19,7 +19,7 @@ export class RecipeCard {
|
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
render() {
|
|
22
|
-
return (h("div", { key: '
|
|
22
|
+
return (h("div", { key: '57023f5420716527cf5bb0a6f775bb62a19f70b6', class: "card", onClick: () => this.cardClick.emit() }, h("div", { key: '137fab4bde9ee40e26217280ba5736b51b96767f', class: "image-wrap" }, this.image ? h("img", { src: this.image, alt: this.recipeTitle }) : h("div", { class: "placeholder" }), h("button", { key: '99b992c4c50082ec42c4b9473b8418d11fe02e10', class: { 'fav-btn': true, active: this.favorite }, onClick: this.onFavoriteClick, "aria-label": "Toggle favorite" }, this.favorite ? '★' : '☆')), h("div", { key: '34a0670cb5e1716e6d7b17d4b1ad3aa5e19b614f', class: "body" }, h("h3", { key: 'c2f5ed25dc9435c10a0b476cebf10e2a7fcfcbd4' }, this.recipeTitle), h("span", { key: 'e4ee0142c7290110c4cb61bd9a3cae4f2503ca69', class: "types" }, this.category && h("span", { key: '0faf05e5d79a532dd5947f4f51fc44ca75f51844', class: "category" }, this.category), this.cuisine && h("span", { key: 'e8aee0b08bed65c359fc589412d89a14ed81f091', class: "cuisine" }, this.cuisine)), h("div", { key: '7c000476afc7687f4318abf6df26ba83bac131e2', class: "actions" }, h("slot", { key: 'e613619696cb0f3967426e1dbb245d23a8913d3d', name: "actions" })))));
|
|
23
23
|
}
|
|
24
24
|
static get is() { return "recipe-card"; }
|
|
25
25
|
static get encapsulation() { return "shadow"; }
|
|
@@ -15,7 +15,7 @@ export class RecipeFilterBar {
|
|
|
15
15
|
}
|
|
16
16
|
render() {
|
|
17
17
|
const cats = Array.isArray(this.categories) ? this.categories : [];
|
|
18
|
-
return (h("div", { key: '
|
|
18
|
+
return (h("div", { key: 'c19ffd90b0eff5c4b9b06602c9432b1210cc27f7', class: "wrap" }, h("button", { key: '3a629b0e211a6b9ab80b015da2d4be44c85f59a1', class: { chip: true, active: this.active === '' }, onClick: () => this.select('') }, "All"), cats.map((c) => (h("button", { class: { chip: true, active: this.active === c }, onClick: () => this.select(c) }, c)))));
|
|
19
19
|
}
|
|
20
20
|
static get is() { return "recipe-filter-bar"; }
|
|
21
21
|
static get encapsulation() { return "shadow"; }
|