@ssejal8/recipe-ui-kit 0.1.0 → 0.1.1

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.
Files changed (191) hide show
  1. package/README.md +108 -277
  2. package/dist/cjs/index-BEr8BsSA.js +1712 -0
  3. package/dist/cjs/index-BEr8BsSA.js.map +1 -0
  4. package/dist/cjs/index.cjs.js +5 -0
  5. package/dist/cjs/index.cjs.js.map +1 -0
  6. package/dist/cjs/loader.cjs.js +15 -0
  7. package/dist/cjs/loader.cjs.js.map +1 -0
  8. package/dist/cjs/recipe-kit.cjs.js +27 -0
  9. package/dist/cjs/recipe-kit.cjs.js.map +1 -0
  10. package/dist/cjs/rk-badge_10.cjs.entry.js +638 -0
  11. package/dist/cjs/rk-badge_10.cjs.entry.js.map +1 -0
  12. package/dist/collection/collection-manifest.json +22 -0
  13. package/dist/collection/components/rk-badge/rk-badge.js +97 -0
  14. package/dist/collection/components/rk-badge/rk-badge.js.map +1 -0
  15. package/dist/collection/components/rk-chip/rk-chip.js +245 -0
  16. package/dist/collection/components/rk-chip/rk-chip.js.map +1 -0
  17. package/dist/collection/components/rk-empty-state/rk-empty-state.js +138 -0
  18. package/dist/collection/components/rk-empty-state/rk-empty-state.js.map +1 -0
  19. package/dist/collection/components/rk-meal-slot/rk-meal-slot.js +312 -0
  20. package/dist/collection/components/rk-meal-slot/rk-meal-slot.js.map +1 -0
  21. package/dist/collection/components/rk-modal/rk-modal.js +256 -0
  22. package/dist/collection/components/rk-modal/rk-modal.js.map +1 -0
  23. package/dist/collection/components/rk-rating/rk-rating.js +228 -0
  24. package/dist/collection/components/rk-rating/rk-rating.js.map +1 -0
  25. package/dist/collection/components/rk-recipe-card/rk-recipe-card.js +366 -0
  26. package/dist/collection/components/rk-recipe-card/rk-recipe-card.js.map +1 -0
  27. package/dist/collection/components/rk-search-bar/rk-search-bar.js +291 -0
  28. package/dist/collection/components/rk-search-bar/rk-search-bar.js.map +1 -0
  29. package/dist/collection/components/rk-segmented-control/rk-segmented-control.js +196 -0
  30. package/dist/collection/components/rk-segmented-control/rk-segmented-control.js.map +1 -0
  31. package/dist/collection/components/rk-tag-input/rk-tag-input.js +264 -0
  32. package/dist/collection/components/rk-tag-input/rk-tag-input.js.map +1 -0
  33. package/dist/collection/index.js +2 -0
  34. package/dist/collection/index.js.map +1 -0
  35. package/dist/components/index.d.ts +35 -0
  36. package/dist/components/index.js +2 -0
  37. package/dist/components/index.js.map +1 -0
  38. package/dist/components/rk-badge.d.ts +11 -0
  39. package/dist/components/rk-badge.js +2 -0
  40. package/dist/components/rk-badge.js.map +1 -0
  41. package/dist/components/rk-chip.d.ts +11 -0
  42. package/dist/components/rk-chip.js +2 -0
  43. package/dist/components/rk-chip.js.map +1 -0
  44. package/dist/components/rk-empty-state.d.ts +11 -0
  45. package/dist/components/rk-empty-state.js +2 -0
  46. package/dist/components/rk-empty-state.js.map +1 -0
  47. package/dist/components/rk-meal-slot.d.ts +11 -0
  48. package/dist/components/rk-meal-slot.js +2 -0
  49. package/dist/components/rk-meal-slot.js.map +1 -0
  50. package/dist/components/rk-modal.d.ts +11 -0
  51. package/dist/components/rk-modal.js +2 -0
  52. package/dist/components/rk-modal.js.map +1 -0
  53. package/dist/components/rk-rating.d.ts +11 -0
  54. package/dist/components/rk-rating.js +2 -0
  55. package/dist/components/rk-rating.js.map +1 -0
  56. package/dist/components/rk-recipe-card.d.ts +11 -0
  57. package/dist/components/rk-recipe-card.js +2 -0
  58. package/dist/components/rk-recipe-card.js.map +1 -0
  59. package/dist/components/rk-search-bar.d.ts +11 -0
  60. package/dist/components/rk-search-bar.js +2 -0
  61. package/dist/components/rk-search-bar.js.map +1 -0
  62. package/dist/components/rk-segmented-control.d.ts +11 -0
  63. package/dist/components/rk-segmented-control.js +2 -0
  64. package/dist/components/rk-segmented-control.js.map +1 -0
  65. package/dist/components/rk-tag-input.d.ts +11 -0
  66. package/dist/components/rk-tag-input.js +2 -0
  67. package/dist/components/rk-tag-input.js.map +1 -0
  68. package/dist/esm/index-Bxo0C8lB.js +1684 -0
  69. package/dist/esm/index-Bxo0C8lB.js.map +1 -0
  70. package/dist/esm/index.js +4 -0
  71. package/dist/esm/index.js.map +1 -0
  72. package/dist/esm/loader.js +13 -0
  73. package/dist/esm/loader.js.map +1 -0
  74. package/dist/esm/recipe-kit.js +23 -0
  75. package/dist/esm/recipe-kit.js.map +1 -0
  76. package/dist/esm/rk-badge_10.entry.js +627 -0
  77. package/dist/esm/rk-badge_10.entry.js.map +1 -0
  78. package/dist/index.cjs.js +1 -0
  79. package/dist/index.js +1 -0
  80. package/dist/recipe-kit/index.esm.js +2 -0
  81. package/dist/recipe-kit/index.esm.js.map +1 -0
  82. package/dist/recipe-kit/p-Bxo0C8lB.js +3 -0
  83. package/dist/recipe-kit/p-Bxo0C8lB.js.map +1 -0
  84. package/dist/recipe-kit/p-fcb955c7.entry.js +2 -0
  85. package/dist/recipe-kit/p-fcb955c7.entry.js.map +1 -0
  86. package/dist/recipe-kit/recipe-kit.css +1 -0
  87. package/dist/recipe-kit/recipe-kit.esm.js +2 -0
  88. package/dist/recipe-kit/recipe-kit.esm.js.map +1 -0
  89. package/dist/recipe-kit/rk-global.css +104 -0
  90. package/dist/types/components/rk-badge/rk-badge.d.ts +15 -0
  91. package/dist/types/components/rk-chip/rk-chip.d.ts +37 -0
  92. package/dist/types/components/rk-empty-state/rk-empty-state.d.ts +19 -0
  93. package/dist/types/components/rk-meal-slot/rk-meal-slot.d.ts +53 -0
  94. package/dist/types/components/rk-modal/rk-modal.d.ts +41 -0
  95. package/dist/types/components/rk-rating/rk-rating.d.ts +26 -0
  96. package/dist/types/components/rk-recipe-card/rk-recipe-card.d.ts +67 -0
  97. package/dist/types/components/rk-search-bar/rk-search-bar.d.ts +39 -0
  98. package/dist/types/components/rk-segmented-control/rk-segmented-control.d.ts +37 -0
  99. package/dist/types/components/rk-tag-input/rk-tag-input.d.ts +35 -0
  100. package/{packages/recipe-kit-stencil/src → dist/types}/components.d.ts +1 -1
  101. package/{packages/recipe-kit-stencil/src/index.ts → dist/types/index.d.ts} +0 -2
  102. package/dist/types/stencil-public-runtime.d.ts +1873 -0
  103. package/loader/cdn.js +1 -0
  104. package/loader/index.cjs.js +1 -0
  105. package/loader/index.d.ts +24 -0
  106. package/loader/index.es2017.js +1 -0
  107. package/loader/index.js +2 -0
  108. package/package.json +84 -22
  109. package/.claude/settings.local.json +0 -10
  110. package/.npmr +0 -1
  111. package/apps/recipe-web/package.json +0 -31
  112. package/apps/recipe-web/src/app.css +0 -418
  113. package/apps/recipe-web/src/app.d.ts +0 -32
  114. package/apps/recipe-web/src/app.html +0 -25
  115. package/apps/recipe-web/src/lib/api/mealdb.ts +0 -240
  116. package/apps/recipe-web/src/lib/components/AppHeader.svelte +0 -290
  117. package/apps/recipe-web/src/lib/components/ConfirmDialog.svelte +0 -46
  118. package/apps/recipe-web/src/lib/components/Modal.svelte +0 -33
  119. package/apps/recipe-web/src/lib/components/RecipeCard.svelte +0 -100
  120. package/apps/recipe-web/src/lib/components/RecipeForm.svelte +0 -560
  121. package/apps/recipe-web/src/lib/components/RecipeGrid.svelte +0 -77
  122. package/apps/recipe-web/src/lib/components/RecipePickerDialog.svelte +0 -185
  123. package/apps/recipe-web/src/lib/components/Toaster.svelte +0 -111
  124. package/apps/recipe-web/src/lib/domain/recipe.ts +0 -130
  125. package/apps/recipe-web/src/lib/domain/validation.ts +0 -189
  126. package/apps/recipe-web/src/lib/stencil/WebComponent.svelte +0 -145
  127. package/apps/recipe-web/src/lib/stencil/register.ts +0 -28
  128. package/apps/recipe-web/src/lib/stores/favorites.svelte.ts +0 -81
  129. package/apps/recipe-web/src/lib/stores/myRecipes.svelte.ts +0 -98
  130. package/apps/recipe-web/src/lib/stores/persisted.svelte.ts +0 -73
  131. package/apps/recipe-web/src/lib/stores/planner.svelte.ts +0 -275
  132. package/apps/recipe-web/src/lib/stores/theme.svelte.ts +0 -67
  133. package/apps/recipe-web/src/lib/stores/toast.svelte.ts +0 -66
  134. package/apps/recipe-web/src/routes/+error.svelte +0 -36
  135. package/apps/recipe-web/src/routes/+layout.svelte +0 -62
  136. package/apps/recipe-web/src/routes/+page.svelte +0 -352
  137. package/apps/recipe-web/src/routes/+page.ts +0 -107
  138. package/apps/recipe-web/src/routes/favorites/+page.svelte +0 -170
  139. package/apps/recipe-web/src/routes/my-recipes/+layout.ts +0 -55
  140. package/apps/recipe-web/src/routes/my-recipes/+page.svelte +0 -180
  141. package/apps/recipe-web/src/routes/my-recipes/[id]/edit/+page.svelte +0 -104
  142. package/apps/recipe-web/src/routes/my-recipes/new/+page.svelte +0 -67
  143. package/apps/recipe-web/src/routes/planner/+page.svelte +0 -422
  144. package/apps/recipe-web/src/routes/recipes/[id]/+page.svelte +0 -538
  145. package/apps/recipe-web/src/routes/recipes/[id]/+page.ts +0 -24
  146. package/apps/recipe-web/static/favicon.svg +0 -8
  147. package/apps/recipe-web/static/robots.txt +0 -2
  148. package/apps/recipe-web/svelte.config.js +0 -35
  149. package/apps/recipe-web/tsconfig.json +0 -14
  150. package/apps/recipe-web/vite.config.ts +0 -23
  151. package/packages/recipe-kit-stencil/README.md +0 -185
  152. package/packages/recipe-kit-stencil/package-lock.json +0 -4772
  153. package/packages/recipe-kit-stencil/package.json +0 -91
  154. package/packages/recipe-kit-stencil/src/components/rk-badge/readme.md +0 -38
  155. package/packages/recipe-kit-stencil/src/components/rk-badge/rk-badge.tsx +0 -31
  156. package/packages/recipe-kit-stencil/src/components/rk-chip/readme.md +0 -52
  157. package/packages/recipe-kit-stencil/src/components/rk-chip/rk-chip.tsx +0 -105
  158. package/packages/recipe-kit-stencil/src/components/rk-empty-state/readme.md +0 -44
  159. package/packages/recipe-kit-stencil/src/components/rk-empty-state/rk-empty-state.tsx +0 -50
  160. package/packages/recipe-kit-stencil/src/components/rk-meal-slot/readme.md +0 -58
  161. package/packages/recipe-kit-stencil/src/components/rk-meal-slot/rk-meal-slot.tsx +0 -182
  162. package/packages/recipe-kit-stencil/src/components/rk-modal/readme.md +0 -57
  163. package/packages/recipe-kit-stencil/src/components/rk-modal/rk-modal.tsx +0 -176
  164. package/packages/recipe-kit-stencil/src/components/rk-rating/readme.md +0 -42
  165. package/packages/recipe-kit-stencil/src/components/rk-rating/rk-rating.tsx +0 -114
  166. package/packages/recipe-kit-stencil/src/components/rk-recipe-card/readme.md +0 -66
  167. package/packages/recipe-kit-stencil/src/components/rk-recipe-card/rk-recipe-card.tsx +0 -179
  168. package/packages/recipe-kit-stencil/src/components/rk-recipe-card/test/rk-recipe-card.spec.tsx +0 -70
  169. package/packages/recipe-kit-stencil/src/components/rk-search-bar/readme.md +0 -67
  170. package/packages/recipe-kit-stencil/src/components/rk-search-bar/rk-search-bar.tsx +0 -152
  171. package/packages/recipe-kit-stencil/src/components/rk-search-bar/test/rk-search-bar.spec.tsx +0 -93
  172. package/packages/recipe-kit-stencil/src/components/rk-segmented-control/readme.md +0 -41
  173. package/packages/recipe-kit-stencil/src/components/rk-segmented-control/rk-segmented-control.tsx +0 -115
  174. package/packages/recipe-kit-stencil/src/components/rk-tag-input/readme.md +0 -47
  175. package/packages/recipe-kit-stencil/src/components/rk-tag-input/rk-tag-input.tsx +0 -181
  176. package/packages/recipe-kit-stencil/src/components/rk-tag-input/test/rk-tag-input.spec.tsx +0 -76
  177. package/packages/recipe-kit-stencil/src/index.html +0 -259
  178. package/packages/recipe-kit-stencil/stencil.config.ts +0 -41
  179. package/packages/recipe-kit-stencil/tsconfig.json +0 -24
  180. /package/{packages/recipe-kit-stencil/LICENSE → LICENSE} +0 -0
  181. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-badge/rk-badge.css +0 -0
  182. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-chip/rk-chip.css +0 -0
  183. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-empty-state/rk-empty-state.css +0 -0
  184. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-meal-slot/rk-meal-slot.css +0 -0
  185. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-modal/rk-modal.css +0 -0
  186. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-rating/rk-rating.css +0 -0
  187. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-recipe-card/rk-recipe-card.css +0 -0
  188. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-search-bar/rk-search-bar.css +0 -0
  189. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-segmented-control/rk-segmented-control.css +0 -0
  190. /package/{packages/recipe-kit-stencil/src → dist/collection}/components/rk-tag-input/rk-tag-input.css +0 -0
  191. /package/{packages/recipe-kit-stencil/src/global → dist/collection}/rk-global.css +0 -0
@@ -0,0 +1,366 @@
1
+ import { h } from "@stencil/core";
2
+ /**
3
+ * The primary recipe tile used across discovery, favorites and search results.
4
+ *
5
+ * All data arrives as individual primitive properties rather than one object
6
+ * prop, so the component works with plain HTML attributes in any framework.
7
+ *
8
+ * @slot - Extra metadata rendered under the title (badges, tags, ratings).
9
+ * @slot actions - Buttons rendered in the card footer (e.g. "Add to plan").
10
+ */
11
+ export class RkRecipeCard {
12
+ constructor() {
13
+ /** Recipe title. */
14
+ this.name = '';
15
+ /** Whether this recipe is currently favorited. */
16
+ this.favorite = false;
17
+ /** `custom` recipes are user-authored and get an "Owned" badge. */
18
+ this.origin = 'api';
19
+ /** Renders a compact horizontal layout, for dense lists and the planner. */
20
+ this.compact = false;
21
+ /** Hides the favorite button entirely (e.g. inside the planner). */
22
+ this.hideFavorite = false;
23
+ this.imageFailed = false;
24
+ this.hasExtra = false;
25
+ this.hasActions = false;
26
+ /**
27
+ * Slot content is optional, and an empty wrapper would still paint padding and
28
+ * a border. Tracking what was actually projected lets the card collapse those
29
+ * regions instead. Re-run on `slotchange` so framework-driven updates count.
30
+ */
31
+ this.syncSlots = () => {
32
+ const elements = Array.from(this.host.children);
33
+ this.hasActions = elements.some(node => node.getAttribute('slot') === 'actions');
34
+ this.hasExtra =
35
+ elements.some(node => !node.hasAttribute('slot')) ||
36
+ Array.from(this.host.childNodes).some(node => node.nodeType === Node.TEXT_NODE && (node.textContent ?? '').trim() !== '');
37
+ };
38
+ this.handleSelect = (event) => {
39
+ // Let the browser handle modified clicks so "open in new tab" keeps working.
40
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
41
+ return;
42
+ }
43
+ event.preventDefault();
44
+ this.rkCardSelect.emit(this.detail);
45
+ };
46
+ this.handleFavorite = (event) => {
47
+ event.preventDefault();
48
+ event.stopPropagation();
49
+ this.rkFavoriteToggle.emit({ ...this.detail, favorite: !this.favorite });
50
+ };
51
+ }
52
+ componentWillLoad() {
53
+ this.syncSlots();
54
+ }
55
+ get detail() {
56
+ return { recipeId: this.recipeId, name: this.name, origin: this.origin };
57
+ }
58
+ render() {
59
+ const showImage = this.image && !this.imageFailed;
60
+ const href = this.href ?? `#${this.recipeId}`;
61
+ return (h("article", { key: 'abc3f8de736b74b1446ced7f2745c5a60b489c24', class: { card: true, 'is-compact': this.compact }, part: "card" }, h("a", { key: 'c401e8d99a43bbc5b4a67f1b79d02a4afd17fefc', class: "media", part: "media", href: href, tabindex: -1, "aria-hidden": "true", onClick: this.handleSelect }, showImage ? (h("img", { src: this.image, alt: "", loading: "lazy", decoding: "async", onError: () => (this.imageFailed = true) })) : (h("span", { class: "media-fallback", "aria-hidden": "true" }, "\uD83C\uDF72")), this.origin === 'custom' && (h("span", { key: 'd73c90426f8727a313d047db677a92184e57d794', class: "owned", part: "owned-badge" }, "Yours"))), !this.hideFavorite && (h("button", { key: '2f8cbaec4403219b0d39529758ef52bf8cb1fb7a', class: { fav: true, 'is-on': this.favorite }, part: "favorite-button", type: "button", onClick: this.handleFavorite, "aria-pressed": String(this.favorite), "aria-label": this.favorite ? `Remove ${this.name} from favorites` : `Add ${this.name} to favorites`, title: this.favorite ? 'Remove from favorites' : 'Add to favorites' }, h("svg", { key: '5766d053203efbf14be2ef9c6f6e1e7d8fa72552', viewBox: "0 0 24 24", stroke: "currentColor", "stroke-width": "1.9", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { key: '1eebb81f40253f26b3ea021dd08cd6fd67b6e2ea', d: "M12 20.5 4.6 13.3a4.7 4.7 0 0 1 0-6.7 4.7 4.7 0 0 1 6.7 0l.7.7.7-.7a4.7 4.7 0 0 1 6.7 0 4.7 4.7 0 0 1 0 6.7Z" })))), h("div", { key: '0dd0feccc789b188cecc42d920e44e39556a9134', class: "body", part: "body" }, h("h3", { key: '29739cf1838d2a2827985104da23e62498c00a00', class: "title", part: "title" }, h("a", { key: 'd42fa3f306da565f8a04179a699fc7b6092839d6', href: href, onClick: this.handleSelect }, this.name)), h("p", { key: '3a16c25552fab648854e3923d6f0a389f916b07f', class: "meta", part: "meta" }, this.category && h("span", { key: 'ea8788f2772055734cc6740fc073c48061ff7b1c', class: "meta-item" }, this.category), this.area && h("span", { key: 'b54bba9cd55cec0296a483efa8a865c8b50dab03', class: "meta-item" }, this.area), this.minutes > 0 && h("span", { key: '11c08808645b3dbd942d5374edf92bcd18af85a1', class: "meta-item" }, this.minutes, " min"), this.servings > 0 && h("span", { key: '28064d47688d06897a3b46ff039d66483e280803', class: "meta-item" }, "Serves ", this.servings)), h("div", { key: '3bf5b7ad91730f16697854287d3853b371d27cf4', class: { extra: true, 'is-empty': !this.hasExtra }, part: "extra" }, h("slot", { key: '1dfe7c29f1d350e85c4cd8122f6fe7e07c60f56f', onSlotchange: this.syncSlots }))), h("footer", { key: '56e115b1e6c46fc5de7a8df9ea005011787ecd51', class: { footer: true, 'is-empty': !this.hasActions }, part: "footer" }, h("slot", { key: 'd07e312d8486a7b761856f5137f24ab95a98c582', name: "actions", onSlotchange: this.syncSlots }))));
62
+ }
63
+ static get is() { return "rk-recipe-card"; }
64
+ static get encapsulation() { return "shadow"; }
65
+ static get originalStyleUrls() {
66
+ return {
67
+ "$": ["rk-recipe-card.css"]
68
+ };
69
+ }
70
+ static get styleUrls() {
71
+ return {
72
+ "$": ["rk-recipe-card.css"]
73
+ };
74
+ }
75
+ static get properties() {
76
+ return {
77
+ "recipeId": {
78
+ "type": "string",
79
+ "mutable": false,
80
+ "complexType": {
81
+ "original": "string",
82
+ "resolved": "string",
83
+ "references": {}
84
+ },
85
+ "required": true,
86
+ "optional": false,
87
+ "docs": {
88
+ "tags": [],
89
+ "text": "Stable identifier echoed back in every event payload."
90
+ },
91
+ "getter": false,
92
+ "setter": false,
93
+ "reflect": false,
94
+ "attribute": "recipe-id"
95
+ },
96
+ "name": {
97
+ "type": "string",
98
+ "mutable": false,
99
+ "complexType": {
100
+ "original": "string",
101
+ "resolved": "string",
102
+ "references": {}
103
+ },
104
+ "required": false,
105
+ "optional": false,
106
+ "docs": {
107
+ "tags": [],
108
+ "text": "Recipe title."
109
+ },
110
+ "getter": false,
111
+ "setter": false,
112
+ "reflect": false,
113
+ "attribute": "name",
114
+ "defaultValue": "''"
115
+ },
116
+ "image": {
117
+ "type": "string",
118
+ "mutable": false,
119
+ "complexType": {
120
+ "original": "string",
121
+ "resolved": "string",
122
+ "references": {}
123
+ },
124
+ "required": false,
125
+ "optional": true,
126
+ "docs": {
127
+ "tags": [],
128
+ "text": "Thumbnail URL."
129
+ },
130
+ "getter": false,
131
+ "setter": false,
132
+ "reflect": false,
133
+ "attribute": "image"
134
+ },
135
+ "category": {
136
+ "type": "string",
137
+ "mutable": false,
138
+ "complexType": {
139
+ "original": "string",
140
+ "resolved": "string",
141
+ "references": {}
142
+ },
143
+ "required": false,
144
+ "optional": true,
145
+ "docs": {
146
+ "tags": [],
147
+ "text": "Category, e.g. \"Dessert\"."
148
+ },
149
+ "getter": false,
150
+ "setter": false,
151
+ "reflect": false,
152
+ "attribute": "category"
153
+ },
154
+ "area": {
155
+ "type": "string",
156
+ "mutable": false,
157
+ "complexType": {
158
+ "original": "string",
159
+ "resolved": "string",
160
+ "references": {}
161
+ },
162
+ "required": false,
163
+ "optional": true,
164
+ "docs": {
165
+ "tags": [],
166
+ "text": "Cuisine / region, e.g. \"Italian\"."
167
+ },
168
+ "getter": false,
169
+ "setter": false,
170
+ "reflect": false,
171
+ "attribute": "area"
172
+ },
173
+ "minutes": {
174
+ "type": "number",
175
+ "mutable": false,
176
+ "complexType": {
177
+ "original": "number",
178
+ "resolved": "number",
179
+ "references": {}
180
+ },
181
+ "required": false,
182
+ "optional": true,
183
+ "docs": {
184
+ "tags": [],
185
+ "text": "Total time in minutes. Hidden when omitted."
186
+ },
187
+ "getter": false,
188
+ "setter": false,
189
+ "reflect": false,
190
+ "attribute": "minutes"
191
+ },
192
+ "servings": {
193
+ "type": "number",
194
+ "mutable": false,
195
+ "complexType": {
196
+ "original": "number",
197
+ "resolved": "number",
198
+ "references": {}
199
+ },
200
+ "required": false,
201
+ "optional": true,
202
+ "docs": {
203
+ "tags": [],
204
+ "text": "Number of servings. Hidden when omitted."
205
+ },
206
+ "getter": false,
207
+ "setter": false,
208
+ "reflect": false,
209
+ "attribute": "servings"
210
+ },
211
+ "favorite": {
212
+ "type": "boolean",
213
+ "mutable": false,
214
+ "complexType": {
215
+ "original": "boolean",
216
+ "resolved": "boolean",
217
+ "references": {}
218
+ },
219
+ "required": false,
220
+ "optional": false,
221
+ "docs": {
222
+ "tags": [],
223
+ "text": "Whether this recipe is currently favorited."
224
+ },
225
+ "getter": false,
226
+ "setter": false,
227
+ "reflect": false,
228
+ "attribute": "favorite",
229
+ "defaultValue": "false"
230
+ },
231
+ "origin": {
232
+ "type": "string",
233
+ "mutable": false,
234
+ "complexType": {
235
+ "original": "'api' | 'custom'",
236
+ "resolved": "\"api\" | \"custom\"",
237
+ "references": {}
238
+ },
239
+ "required": false,
240
+ "optional": false,
241
+ "docs": {
242
+ "tags": [],
243
+ "text": "`custom` recipes are user-authored and get an \"Owned\" badge."
244
+ },
245
+ "getter": false,
246
+ "setter": false,
247
+ "reflect": false,
248
+ "attribute": "origin",
249
+ "defaultValue": "'api'"
250
+ },
251
+ "href": {
252
+ "type": "string",
253
+ "mutable": false,
254
+ "complexType": {
255
+ "original": "string",
256
+ "resolved": "string",
257
+ "references": {}
258
+ },
259
+ "required": false,
260
+ "optional": true,
261
+ "docs": {
262
+ "tags": [],
263
+ "text": "Real href used for accessibility, SEO and middle-click / open-in-new-tab."
264
+ },
265
+ "getter": false,
266
+ "setter": false,
267
+ "reflect": false,
268
+ "attribute": "href"
269
+ },
270
+ "compact": {
271
+ "type": "boolean",
272
+ "mutable": false,
273
+ "complexType": {
274
+ "original": "boolean",
275
+ "resolved": "boolean",
276
+ "references": {}
277
+ },
278
+ "required": false,
279
+ "optional": false,
280
+ "docs": {
281
+ "tags": [],
282
+ "text": "Renders a compact horizontal layout, for dense lists and the planner."
283
+ },
284
+ "getter": false,
285
+ "setter": false,
286
+ "reflect": false,
287
+ "attribute": "compact",
288
+ "defaultValue": "false"
289
+ },
290
+ "hideFavorite": {
291
+ "type": "boolean",
292
+ "mutable": false,
293
+ "complexType": {
294
+ "original": "boolean",
295
+ "resolved": "boolean",
296
+ "references": {}
297
+ },
298
+ "required": false,
299
+ "optional": false,
300
+ "docs": {
301
+ "tags": [],
302
+ "text": "Hides the favorite button entirely (e.g. inside the planner)."
303
+ },
304
+ "getter": false,
305
+ "setter": false,
306
+ "reflect": false,
307
+ "attribute": "hide-favorite",
308
+ "defaultValue": "false"
309
+ }
310
+ };
311
+ }
312
+ static get states() {
313
+ return {
314
+ "imageFailed": {},
315
+ "hasExtra": {},
316
+ "hasActions": {}
317
+ };
318
+ }
319
+ static get events() {
320
+ return [{
321
+ "method": "rkCardSelect",
322
+ "name": "rkCardSelect",
323
+ "bubbles": true,
324
+ "cancelable": true,
325
+ "composed": true,
326
+ "docs": {
327
+ "tags": [],
328
+ "text": "Emitted on primary activation. The host app performs the navigation."
329
+ },
330
+ "complexType": {
331
+ "original": "RkRecipeCardSelectDetail",
332
+ "resolved": "RkRecipeCardSelectDetail",
333
+ "references": {
334
+ "RkRecipeCardSelectDetail": {
335
+ "location": "local",
336
+ "path": "/Users/sejal.sharma/NAGP/recipe-ui/packages/recipe-ui-kit/src/components/rk-recipe-card/rk-recipe-card.tsx",
337
+ "id": "src/components/rk-recipe-card/rk-recipe-card.tsx::RkRecipeCardSelectDetail"
338
+ }
339
+ }
340
+ }
341
+ }, {
342
+ "method": "rkFavoriteToggle",
343
+ "name": "rkFavoriteToggle",
344
+ "bubbles": true,
345
+ "cancelable": true,
346
+ "composed": true,
347
+ "docs": {
348
+ "tags": [],
349
+ "text": "Emitted when the favorite button is pressed."
350
+ },
351
+ "complexType": {
352
+ "original": "RkFavoriteToggleDetail",
353
+ "resolved": "RkFavoriteToggleDetail",
354
+ "references": {
355
+ "RkFavoriteToggleDetail": {
356
+ "location": "local",
357
+ "path": "/Users/sejal.sharma/NAGP/recipe-ui/packages/recipe-ui-kit/src/components/rk-recipe-card/rk-recipe-card.tsx",
358
+ "id": "src/components/rk-recipe-card/rk-recipe-card.tsx::RkFavoriteToggleDetail"
359
+ }
360
+ }
361
+ }
362
+ }];
363
+ }
364
+ static get elementRef() { return "host"; }
365
+ }
366
+ //# sourceMappingURL=rk-recipe-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rk-recipe-card.js","sourceRoot":"","sources":["../../../src/components/rk-recipe-card/rk-recipe-card.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, Element, Event, EventEmitter, h, Prop, State } from '@stencil/core';\n\nexport interface RkRecipeCardSelectDetail {\n recipeId: string;\n name: string;\n origin: 'api' | 'custom';\n}\n\nexport interface RkFavoriteToggleDetail {\n recipeId: string;\n name: string;\n origin: 'api' | 'custom';\n /** The state the host app should move *to*. */\n favorite: boolean;\n}\n\n/**\n * The primary recipe tile used across discovery, favorites and search results.\n *\n * All data arrives as individual primitive properties rather than one object\n * prop, so the component works with plain HTML attributes in any framework.\n *\n * @slot - Extra metadata rendered under the title (badges, tags, ratings).\n * @slot actions - Buttons rendered in the card footer (e.g. \"Add to plan\").\n */\n@Component({\n tag: 'rk-recipe-card',\n styleUrl: 'rk-recipe-card.css',\n shadow: true,\n})\nexport class RkRecipeCard {\n @Element() host!: HTMLElement;\n\n /** Stable identifier echoed back in every event payload. */\n @Prop() recipeId!: string;\n\n /** Recipe title. */\n @Prop() name = '';\n\n /** Thumbnail URL. */\n @Prop() image?: string;\n\n /** Category, e.g. \"Dessert\". */\n @Prop() category?: string;\n\n /** Cuisine / region, e.g. \"Italian\". */\n @Prop() area?: string;\n\n /** Total time in minutes. Hidden when omitted. */\n @Prop() minutes?: number;\n\n /** Number of servings. Hidden when omitted. */\n @Prop() servings?: number;\n\n /** Whether this recipe is currently favorited. */\n @Prop() favorite = false;\n\n /** `custom` recipes are user-authored and get an \"Owned\" badge. */\n @Prop() origin: 'api' | 'custom' = 'api';\n\n /** Real href used for accessibility, SEO and middle-click / open-in-new-tab. */\n @Prop() href?: string;\n\n /** Renders a compact horizontal layout, for dense lists and the planner. */\n @Prop() compact = false;\n\n /** Hides the favorite button entirely (e.g. inside the planner). */\n @Prop() hideFavorite = false;\n\n /** Emitted on primary activation. The host app performs the navigation. */\n @Event({ eventName: 'rkCardSelect' }) rkCardSelect!: EventEmitter<RkRecipeCardSelectDetail>;\n\n /** Emitted when the favorite button is pressed. */\n @Event({ eventName: 'rkFavoriteToggle' }) rkFavoriteToggle!: EventEmitter<RkFavoriteToggleDetail>;\n\n @State() private imageFailed = false;\n @State() private hasExtra = false;\n @State() private hasActions = false;\n\n componentWillLoad() {\n this.syncSlots();\n }\n\n /**\n * Slot content is optional, and an empty wrapper would still paint padding and\n * a border. Tracking what was actually projected lets the card collapse those\n * regions instead. Re-run on `slotchange` so framework-driven updates count.\n */\n private syncSlots = () => {\n const elements = Array.from(this.host.children);\n this.hasActions = elements.some(node => node.getAttribute('slot') === 'actions');\n this.hasExtra =\n elements.some(node => !node.hasAttribute('slot')) ||\n Array.from(this.host.childNodes).some(node => node.nodeType === Node.TEXT_NODE && (node.textContent ?? '').trim() !== '');\n };\n\n private get detail(): RkRecipeCardSelectDetail {\n return { recipeId: this.recipeId, name: this.name, origin: this.origin };\n }\n\n private handleSelect = (event: MouseEvent) => {\n // Let the browser handle modified clicks so \"open in new tab\" keeps working.\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {\n return;\n }\n event.preventDefault();\n this.rkCardSelect.emit(this.detail);\n };\n\n private handleFavorite = (event: MouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n this.rkFavoriteToggle.emit({ ...this.detail, favorite: !this.favorite });\n };\n\n render() {\n const showImage = this.image && !this.imageFailed;\n const href = this.href ?? `#${this.recipeId}`;\n\n return (\n <article class={{ card: true, 'is-compact': this.compact }} part=\"card\">\n <a class=\"media\" part=\"media\" href={href} tabindex={-1} aria-hidden=\"true\" onClick={this.handleSelect}>\n {showImage ? (\n <img src={this.image} alt=\"\" loading=\"lazy\" decoding=\"async\" onError={() => (this.imageFailed = true)} />\n ) : (\n <span class=\"media-fallback\" aria-hidden=\"true\">\n 🍲\n </span>\n )}\n\n {this.origin === 'custom' && (\n <span class=\"owned\" part=\"owned-badge\">\n Yours\n </span>\n )}\n </a>\n\n {!this.hideFavorite && (\n <button\n class={{ fav: true, 'is-on': this.favorite }}\n part=\"favorite-button\"\n type=\"button\"\n onClick={this.handleFavorite}\n aria-pressed={String(this.favorite)}\n aria-label={this.favorite ? `Remove ${this.name} from favorites` : `Add ${this.name} to favorites`}\n title={this.favorite ? 'Remove from favorites' : 'Add to favorites'}\n >\n <svg viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"1.9\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M12 20.5 4.6 13.3a4.7 4.7 0 0 1 0-6.7 4.7 4.7 0 0 1 6.7 0l.7.7.7-.7a4.7 4.7 0 0 1 6.7 0 4.7 4.7 0 0 1 0 6.7Z\" />\n </svg>\n </button>\n )}\n\n <div class=\"body\" part=\"body\">\n <h3 class=\"title\" part=\"title\">\n <a href={href} onClick={this.handleSelect}>\n {this.name}\n </a>\n </h3>\n\n <p class=\"meta\" part=\"meta\">\n {this.category && <span class=\"meta-item\">{this.category}</span>}\n {this.area && <span class=\"meta-item\">{this.area}</span>}\n {this.minutes > 0 && <span class=\"meta-item\">{this.minutes} min</span>}\n {this.servings > 0 && <span class=\"meta-item\">Serves {this.servings}</span>}\n </p>\n\n <div class={{ extra: true, 'is-empty': !this.hasExtra }} part=\"extra\">\n <slot onSlotchange={this.syncSlots} />\n </div>\n </div>\n\n <footer class={{ footer: true, 'is-empty': !this.hasActions }} part=\"footer\">\n <slot name=\"actions\" onSlotchange={this.syncSlots} />\n </footer>\n </article>\n );\n }\n}\n"]}