recipe-planner-ui 1.3.1 → 1.5.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.
Files changed (48) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/recipe-planner-ui.cjs.js +1 -1
  3. package/dist/cjs/rp-day-slot.cjs.entry.js +161 -17
  4. package/dist/cjs/rp-filter-chips_6.cjs.entry.js +611 -0
  5. package/dist/cjs/rp-filter-menu.cjs.entry.js +5 -5
  6. package/dist/collection/collection-manifest.json +1 -0
  7. package/dist/collection/components/rp-day-slot/rp-day-slot.css +27 -14
  8. package/dist/collection/components/rp-day-slot/rp-day-slot.js +163 -18
  9. package/dist/collection/components/rp-filter-chips/rp-filter-chips.js +1 -1
  10. package/dist/collection/components/rp-filter-menu/rp-filter-menu.css +19 -2
  11. package/dist/collection/components/rp-filter-menu/rp-filter-menu.js +4 -4
  12. package/dist/collection/components/rp-ingredient-list/rp-ingredient-list.js +2 -2
  13. package/dist/collection/components/rp-modal/rp-modal.css +20 -0
  14. package/dist/collection/components/rp-recipe-card/rp-recipe-card.css +44 -1
  15. package/dist/collection/components/rp-recipe-card/rp-recipe-card.js +57 -2
  16. package/dist/collection/components/rp-search-bar/rp-search-bar.css +33 -2
  17. package/dist/collection/components/rp-search-bar/rp-search-bar.js +1 -1
  18. package/dist/collection/components/rp-select/rp-select.css +205 -0
  19. package/dist/collection/components/rp-select/rp-select.js +559 -0
  20. package/dist/components/p-q8kKM7W4.js +1 -0
  21. package/dist/components/rp-day-slot.js +1 -1
  22. package/dist/components/rp-filter-chips.js +1 -1
  23. package/dist/components/rp-filter-menu.js +1 -1
  24. package/dist/components/rp-ingredient-list.js +1 -1
  25. package/dist/components/rp-modal.js +1 -1
  26. package/dist/components/rp-recipe-card.js +1 -1
  27. package/dist/components/rp-search-bar.js +1 -1
  28. package/dist/components/rp-select.d.ts +11 -0
  29. package/dist/components/rp-select.js +1 -0
  30. package/dist/esm/loader.js +1 -1
  31. package/dist/esm/recipe-planner-ui.js +1 -1
  32. package/dist/esm/rp-day-slot.entry.js +162 -18
  33. package/dist/esm/rp-filter-chips_6.entry.js +604 -0
  34. package/dist/esm/rp-filter-menu.entry.js +5 -5
  35. package/dist/recipe-planner-ui/{p-811d8206.entry.js → p-7a8ee97f.entry.js} +1 -1
  36. package/dist/recipe-planner-ui/p-7f595239.entry.js +1 -0
  37. package/dist/recipe-planner-ui/p-dcb370be.entry.js +1 -0
  38. package/dist/recipe-planner-ui/recipe-planner-ui.css +1 -1
  39. package/dist/recipe-planner-ui/recipe-planner-ui.esm.js +1 -1
  40. package/dist/types/components/rp-day-slot/rp-day-slot.d.ts +39 -3
  41. package/dist/types/components/rp-recipe-card/rp-recipe-card.d.ts +17 -0
  42. package/dist/types/components/rp-select/rp-select.d.ts +106 -0
  43. package/dist/types/components.d.ts +199 -2
  44. package/package.json +1 -1
  45. package/dist/cjs/rp-filter-chips_5.cjs.entry.js +0 -277
  46. package/dist/esm/rp-filter-chips_5.entry.js +0 -271
  47. package/dist/recipe-planner-ui/p-9018ce87.entry.js +0 -1
  48. package/dist/recipe-planner-ui/p-9e84a578.entry.js +0 -1
@@ -6,7 +6,7 @@ var appGlobals = require('./app-globals-V2Kpy_OQ.js');
6
6
  const defineCustomElements = async (win, options) => {
7
7
  if (typeof window === 'undefined') return undefined;
8
8
  await appGlobals.globalScripts();
9
- return index.bootstrapLazy([["rp-filter-chips_5.cjs",[[514,"rp-filter-chips",{"options":[16],"selected":[1],"label":[1]}],[774,"rp-ingredient-list",{"items":[16]}],[774,"rp-modal",{"open":[516],"heading":[1],"focusFirstField":[64]},null,{"open":[{"onOpenChange":0}]}],[774,"rp-recipe-card",{"recipeId":[1,"recipe-id"],"recipeTitle":[1,"recipe-title"],"image":[1],"category":[1],"area":[1],"minutes":[2],"favorite":[516],"imageLoading":[32],"imageFailed":[32],"pulsing":[32]}],[514,"rp-search-bar",{"value":[1],"placeholder":[1],"label":[1],"draft":[32]},null,{"value":[{"onValueChange":0}]}]]],["rp-day-slot.cjs",[[774,"rp-day-slot",{"day":[1],"dayLabel":[1,"day-label"],"meals":[16],"days":[16],"dayLabels":[16],"normalized":[32],"dropActive":[32],"draggingId":[32]}]]],["rp-filter-menu.cjs",[[514,"rp-filter-menu",{"label":[1],"options":[16],"selected":[1],"searchPlaceholder":[1,"search-placeholder"],"searchable":[4],"open":[1540],"filterText":[32],"activeIndex":[32]},[[5,"pointerdown","onDocumentPointerDown"],[4,"keydown","onDocumentKeydown"]],{"open":[{"onOpenChange":0}]}]]]], options);
9
+ return index.bootstrapLazy([["rp-day-slot.cjs",[[774,"rp-day-slot",{"day":[513],"dayLabel":[1,"day-label"],"meals":[16],"days":[16],"dayLabels":[16],"normalized":[32],"dropActive":[32],"draggingId":[32]}]]],["rp-filter-menu.cjs",[[514,"rp-filter-menu",{"label":[1],"options":[16],"selected":[1],"searchPlaceholder":[1,"search-placeholder"],"searchable":[4],"open":[1540],"filterText":[32],"activeIndex":[32]},[[5,"pointerdown","onDocumentPointerDown"],[4,"keydown","onDocumentKeydown"]],{"open":[{"onOpenChange":0}]}]]],["rp-filter-chips_6.cjs",[[514,"rp-filter-chips",{"options":[16],"selected":[1],"label":[1]}],[774,"rp-ingredient-list",{"items":[16]}],[774,"rp-modal",{"open":[516],"heading":[1],"focusFirstField":[64]},null,{"open":[{"onOpenChange":0}]}],[774,"rp-recipe-card",{"recipeId":[1,"recipe-id"],"recipeTitle":[1,"recipe-title"],"image":[1],"category":[1],"href":[1],"hrefLabel":[1,"href-label"],"area":[1],"minutes":[2],"favorite":[516],"imageLoading":[32],"imageFailed":[32],"pulsing":[32]}],[514,"rp-search-bar",{"value":[1],"placeholder":[1],"label":[1],"draft":[32]},null,{"value":[{"onValueChange":0}]}],[514,"rp-select",{"options":[16],"value":[1025],"label":[1],"placeholder":[1],"open":[1540],"disabled":[516],"compact":[516],"dropUp":[1540,"drop-up"],"activeIndex":[32],"focusControl":[64]},[[5,"pointerdown","onDocumentPointerDown"]],{"open":[{"onOpenChange":0}],"options":[{"onOptionsChange":0}]}]]]], options);
10
10
  };
11
11
 
12
12
  exports.setNonce = index.setNonce;
@@ -19,7 +19,7 @@ var patchBrowser = () => {
19
19
 
20
20
  patchBrowser().then(async (options) => {
21
21
  await appGlobals.globalScripts();
22
- return index.bootstrapLazy([["rp-filter-chips_5.cjs",[[514,"rp-filter-chips",{"options":[16],"selected":[1],"label":[1]}],[774,"rp-ingredient-list",{"items":[16]}],[774,"rp-modal",{"open":[516],"heading":[1],"focusFirstField":[64]},null,{"open":[{"onOpenChange":0}]}],[774,"rp-recipe-card",{"recipeId":[1,"recipe-id"],"recipeTitle":[1,"recipe-title"],"image":[1],"category":[1],"area":[1],"minutes":[2],"favorite":[516],"imageLoading":[32],"imageFailed":[32],"pulsing":[32]}],[514,"rp-search-bar",{"value":[1],"placeholder":[1],"label":[1],"draft":[32]},null,{"value":[{"onValueChange":0}]}]]],["rp-day-slot.cjs",[[774,"rp-day-slot",{"day":[1],"dayLabel":[1,"day-label"],"meals":[16],"days":[16],"dayLabels":[16],"normalized":[32],"dropActive":[32],"draggingId":[32]}]]],["rp-filter-menu.cjs",[[514,"rp-filter-menu",{"label":[1],"options":[16],"selected":[1],"searchPlaceholder":[1,"search-placeholder"],"searchable":[4],"open":[1540],"filterText":[32],"activeIndex":[32]},[[5,"pointerdown","onDocumentPointerDown"],[4,"keydown","onDocumentKeydown"]],{"open":[{"onOpenChange":0}]}]]]], options);
22
+ return index.bootstrapLazy([["rp-day-slot.cjs",[[774,"rp-day-slot",{"day":[513],"dayLabel":[1,"day-label"],"meals":[16],"days":[16],"dayLabels":[16],"normalized":[32],"dropActive":[32],"draggingId":[32]}]]],["rp-filter-menu.cjs",[[514,"rp-filter-menu",{"label":[1],"options":[16],"selected":[1],"searchPlaceholder":[1,"search-placeholder"],"searchable":[4],"open":[1540],"filterText":[32],"activeIndex":[32]},[[5,"pointerdown","onDocumentPointerDown"],[4,"keydown","onDocumentKeydown"]],{"open":[{"onOpenChange":0}]}]]],["rp-filter-chips_6.cjs",[[514,"rp-filter-chips",{"options":[16],"selected":[1],"label":[1]}],[774,"rp-ingredient-list",{"items":[16]}],[774,"rp-modal",{"open":[516],"heading":[1],"focusFirstField":[64]},null,{"open":[{"onOpenChange":0}]}],[774,"rp-recipe-card",{"recipeId":[1,"recipe-id"],"recipeTitle":[1,"recipe-title"],"image":[1],"category":[1],"href":[1],"hrefLabel":[1,"href-label"],"area":[1],"minutes":[2],"favorite":[516],"imageLoading":[32],"imageFailed":[32],"pulsing":[32]}],[514,"rp-search-bar",{"value":[1],"placeholder":[1],"label":[1],"draft":[32]},null,{"value":[{"onValueChange":0}]}],[514,"rp-select",{"options":[16],"value":[1025],"label":[1],"placeholder":[1],"open":[1540],"disabled":[516],"compact":[516],"dropUp":[1540,"drop-up"],"activeIndex":[32],"focusControl":[64]},[[5,"pointerdown","onDocumentPointerDown"]],{"open":[{"onOpenChange":0}],"options":[{"onOptionsChange":0}]}]]]], options);
23
23
  });
24
24
 
25
25
  exports.setNonce = index.setNonce;
@@ -2,7 +2,7 @@
2
2
 
3
3
  var index = require('./index-CrJlwqe_.js');
4
4
 
5
- const rpDaySlotCss = () => `.sc-rp-day-slot-h{display:block;font-family:var(--rp-font-sans);color:var(--rp-color-text)}.slot.sc-rp-day-slot{display:flex;flex-direction:column;height:100%;min-height:200px;overflow:hidden;background:var(--rp-color-surface);border:1px solid var(--rp-color-border);border-radius:var(--rp-radius-lg);box-shadow:var(--rp-shadow-xs);transition:border-color var(--rp-duration) var(--rp-ease), box-shadow var(--rp-duration) var(--rp-ease), background-color var(--rp-duration) var(--rp-ease)}.slot.is-empty.sc-rp-day-slot{background:var(--rp-color-surface-sunken);border-style:dashed}.slot.is-drop-active.sc-rp-day-slot{background:var(--rp-color-highlight-soft);border-style:solid;border-color:var(--rp-color-highlight);box-shadow:var(--rp-shadow-md), inset 0 0 0 1px var(--rp-color-highlight)}.head.sc-rp-day-slot{display:flex;gap:var(--rp-space-2);align-items:center;justify-content:space-between;padding:var(--rp-space-3);border-bottom:1px solid var(--rp-color-border)}.day.sc-rp-day-slot{min-width:0;margin:0;overflow:hidden;font-size:var(--rp-font-size-xs);font-weight:700;letter-spacing:0.08em;text-transform:uppercase;text-overflow:ellipsis;white-space:nowrap;color:var(--rp-color-text-muted)}.head-right.sc-rp-day-slot{display:flex;flex-shrink:0;gap:var(--rp-space-2);align-items:center}.count.sc-rp-day-slot{display:grid;place-items:center;min-width:20px;height:20px;padding:0 6px;font-size:0.6875rem;font-weight:700;font-variant-numeric:tabular-nums;color:var(--rp-caramel-600);background:var(--rp-color-highlight-soft);border-radius:var(--rp-radius-pill)}.add.sc-rp-day-slot{display:grid;place-items:center;width:26px;height:26px;padding:0;cursor:pointer;color:var(--rp-color-accent-contrast);background:var(--rp-color-accent);border:none;border-radius:50%;transition:transform var(--rp-duration-fast) var(--rp-ease), background-color var(--rp-duration-fast) var(--rp-ease)}.add.sc-rp-day-slot svg.sc-rp-day-slot{fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}.add.sc-rp-day-slot:hover{background:var(--rp-color-highlight);transform:rotate(90deg) scale(1.1)}.add.sc-rp-day-slot:active{transform:rotate(90deg) scale(0.92)}.meals.sc-rp-day-slot{flex:1;margin:0;padding:var(--rp-space-2);list-style:none;display:flex;flex-direction:column;gap:var(--rp-space-2)}.meal.sc-rp-day-slot{position:relative;padding:var(--rp-space-3) var(--rp-space-3) var(--rp-space-2);cursor:grab;background:var(--rp-color-surface-sunken);border:1px solid var(--rp-color-border);border-radius:var(--rp-radius-md);transition:transform var(--rp-duration-fast) var(--rp-ease), box-shadow var(--rp-duration-fast) var(--rp-ease), opacity var(--rp-duration-fast) var(--rp-ease)}.meal.sc-rp-day-slot:hover{background:var(--rp-color-surface);box-shadow:var(--rp-shadow-sm);transform:translateY(-1px)}.meal.sc-rp-day-slot:active{cursor:grabbing}.meal.is-dragging.sc-rp-day-slot{opacity:0.4;box-shadow:none;transform:none}.grip.sc-rp-day-slot{position:absolute;inset-block-start:var(--rp-space-2);inset-inline-end:var(--rp-space-2);display:block;opacity:0;transition:opacity var(--rp-duration-fast) var(--rp-ease)}.grip.sc-rp-day-slot svg.sc-rp-day-slot{display:block;fill:var(--rp-color-text-subtle)}.meal.sc-rp-day-slot:hover .grip.sc-rp-day-slot{opacity:1}.meal-title.sc-rp-day-slot{display:block;padding-inline-end:var(--rp-space-4);font-size:var(--rp-font-size-sm);font-weight:500;line-height:1.35;color:var(--rp-color-text)}.meal-actions.sc-rp-day-slot{display:flex;gap:var(--rp-space-1);align-items:center;justify-content:space-between;margin-top:var(--rp-space-2)}.move-select.sc-rp-day-slot{max-width:100%;padding:3px var(--rp-space-2);font:inherit;font-size:var(--rp-font-size-xs);color:var(--rp-color-text-muted);cursor:pointer;background:var(--rp-color-surface);border:1px solid var(--rp-color-border);border-radius:var(--rp-radius-sm);transition:border-color var(--rp-duration-fast) var(--rp-ease)}.move-select.sc-rp-day-slot:hover{border-color:var(--rp-color-border-strong)}.remove.sc-rp-day-slot{display:grid;place-items:center;width:24px;height:24px;padding:0;color:var(--rp-color-text-subtle);cursor:pointer;background:none;border:none;border-radius:var(--rp-radius-sm);transition:color var(--rp-duration-fast) var(--rp-ease), background-color var(--rp-duration-fast) var(--rp-ease)}.remove.sc-rp-day-slot svg.sc-rp-day-slot{fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}.remove.sc-rp-day-slot:hover{color:var(--rp-color-danger);background:var(--rp-color-danger-soft)}.empty.sc-rp-day-slot{display:flex;flex:1;flex-direction:column;gap:var(--rp-space-2);align-items:center;justify-content:center;padding:var(--rp-space-4) var(--rp-space-3);text-align:center}.empty-icon.sc-rp-day-slot{fill:none;stroke:var(--rp-color-text-subtle);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}.empty-text.sc-rp-day-slot{margin:0;font-size:var(--rp-font-size-xs);color:var(--rp-color-text-subtle)}.add.sc-rp-day-slot:focus-visible,.remove.sc-rp-day-slot:focus-visible,.move-select.sc-rp-day-slot:focus-visible{outline:var(--rp-focus-ring);outline-offset:var(--rp-focus-offset)}.sr-only.sc-rp-day-slot{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media (prefers-reduced-motion: reduce){.slot.sc-rp-day-slot,.meal.sc-rp-day-slot,.add.sc-rp-day-slot,.grip.sc-rp-day-slot,.remove.sc-rp-day-slot,.move-select.sc-rp-day-slot{transition:none}.meal.sc-rp-day-slot:hover,.add.sc-rp-day-slot:hover,.add.sc-rp-day-slot:active{transform:none}.grip.sc-rp-day-slot{opacity:1}}`;
5
+ const rpDaySlotCss = () => `.sc-rp-day-slot-h{display:block;font-family:var(--rp-font-sans);color:var(--rp-color-text)}.slot.sc-rp-day-slot{display:flex;flex-direction:column;height:100%;min-height:200px;overflow:hidden;background:var(--rp-color-surface);border:1px solid var(--rp-color-border);border-radius:var(--rp-radius-lg);box-shadow:var(--rp-shadow-xs);transition:border-color var(--rp-duration) var(--rp-ease), box-shadow var(--rp-duration) var(--rp-ease), background-color var(--rp-duration) var(--rp-ease)}.slot.is-empty.sc-rp-day-slot{background:var(--rp-color-surface-sunken);border-style:dashed}.slot.is-drop-active.sc-rp-day-slot{background:var(--rp-color-highlight-soft);border-style:solid;border-color:var(--rp-color-highlight);box-shadow:var(--rp-shadow-md), inset 0 0 0 1px var(--rp-color-highlight)}.head.sc-rp-day-slot{display:flex;gap:var(--rp-space-1);align-items:center;justify-content:space-between;padding:var(--rp-space-3) var(--rp-space-2) var(--rp-space-3) var(--rp-space-3);border-bottom:1px solid var(--rp-color-border)}.day.sc-rp-day-slot{min-width:0;margin:0;overflow:hidden;font-size:var(--rp-font-size-xs);font-weight:700;letter-spacing:0.08em;text-transform:uppercase;text-overflow:ellipsis;white-space:nowrap;color:var(--rp-color-text-muted)}.head-right.sc-rp-day-slot{display:flex;flex-shrink:0;gap:var(--rp-space-2);align-items:center}.count.sc-rp-day-slot{display:grid;place-items:center;min-width:20px;height:20px;padding:0 6px;font-size:0.6875rem;font-weight:700;font-variant-numeric:tabular-nums;color:var(--rp-caramel-600);background:var(--rp-color-highlight-soft);border-radius:var(--rp-radius-pill)}.add.sc-rp-day-slot{display:grid;place-items:center;width:26px;height:26px;padding:0;cursor:pointer;color:var(--rp-color-accent-contrast);background:var(--rp-color-accent);border:none;border-radius:50%;transition:transform var(--rp-duration-fast) var(--rp-ease), background-color var(--rp-duration-fast) var(--rp-ease)}.add.sc-rp-day-slot svg.sc-rp-day-slot{fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}.add.sc-rp-day-slot:hover{background:var(--rp-color-highlight);transform:rotate(90deg) scale(1.1)}.add.sc-rp-day-slot:active{transform:rotate(90deg) scale(0.92)}.meals.sc-rp-day-slot{flex:1;margin:0;padding:var(--rp-space-2);list-style:none;display:flex;flex-direction:column;gap:var(--rp-space-2)}.meal.sc-rp-day-slot{position:relative;padding:var(--rp-space-3) var(--rp-space-3) var(--rp-space-2);cursor:grab;touch-action:pan-y;background:var(--rp-color-surface-sunken);border:1px solid var(--rp-color-border);border-radius:var(--rp-radius-md);transition:transform var(--rp-duration-fast) var(--rp-ease), box-shadow var(--rp-duration-fast) var(--rp-ease), opacity var(--rp-duration-fast) var(--rp-ease)}.meal.sc-rp-day-slot:hover{background:var(--rp-color-surface);box-shadow:var(--rp-shadow-sm);transform:translateY(-1px)}.meal.sc-rp-day-slot:active{cursor:grabbing}.meal.is-dragging.sc-rp-day-slot{opacity:0.4;box-shadow:none;transform:none}.grip.sc-rp-day-slot{position:absolute;inset-block-start:var(--rp-space-2);inset-inline-end:var(--rp-space-2);display:block;opacity:0;transition:opacity var(--rp-duration-fast) var(--rp-ease)}.grip.sc-rp-day-slot svg.sc-rp-day-slot{display:block;fill:var(--rp-color-text-subtle)}.meal.sc-rp-day-slot:hover .grip.sc-rp-day-slot{opacity:1}.meal-title.sc-rp-day-slot{display:block;padding-inline-end:var(--rp-space-4);font-size:var(--rp-font-size-sm);font-weight:500;line-height:1.35;color:var(--rp-color-text)}.meal-actions.sc-rp-day-slot{display:flex;gap:var(--rp-space-1);align-items:center;justify-content:space-between;margin-top:var(--rp-space-2)}.move-select.sc-rp-day-slot{min-width:0;position:relative;z-index:1}.meal.sc-rp-day-slot:has(rp-select[open]),.meals.sc-rp-day-slot:has(rp-select[open]){overflow:visible}.slot.sc-rp-day-slot:has(rp-select[open]){overflow:visible}.meal.sc-rp-day-slot:has(rp-select[open]){z-index:3}.remove.sc-rp-day-slot{display:grid;place-items:center;width:24px;height:24px;padding:0;color:var(--rp-color-text-subtle);cursor:pointer;background:none;border:none;border-radius:var(--rp-radius-sm);transition:color var(--rp-duration-fast) var(--rp-ease), background-color var(--rp-duration-fast) var(--rp-ease)}.remove.sc-rp-day-slot svg.sc-rp-day-slot{fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}.remove.sc-rp-day-slot:hover{color:var(--rp-color-danger);background:var(--rp-color-danger-soft)}.empty.sc-rp-day-slot{display:flex;flex:1;flex-direction:column;gap:var(--rp-space-2);align-items:center;justify-content:center;padding:var(--rp-space-4) var(--rp-space-3);text-align:center}.empty-icon.sc-rp-day-slot{fill:none;stroke:var(--rp-color-text-subtle);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}.empty-text.sc-rp-day-slot{margin:0;font-size:var(--rp-font-size-xs);color:var(--rp-color-text-subtle)}.add.sc-rp-day-slot:focus-visible,.remove.sc-rp-day-slot:focus-visible,.move-select.sc-rp-day-slot:focus-visible{outline:var(--rp-focus-ring);outline-offset:var(--rp-focus-offset)}.sr-only.sc-rp-day-slot{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media (prefers-reduced-motion: reduce){.slot.sc-rp-day-slot,.meal.sc-rp-day-slot,.add.sc-rp-day-slot,.grip.sc-rp-day-slot,.remove.sc-rp-day-slot,.move-select.sc-rp-day-slot{transition:none}.meal.sc-rp-day-slot:hover,.add.sc-rp-day-slot:hover,.add.sc-rp-day-slot:active{transform:none}.grip.sc-rp-day-slot{opacity:1}}`;
6
6
 
7
7
  const DaySlot = class {
8
8
  constructor(hostRef) {
@@ -11,7 +11,9 @@ const DaySlot = class {
11
11
  this.rpRemoveMeal = index.createEvent(this, "rpRemoveMeal");
12
12
  this.rpMoveMeal = index.createEvent(this, "rpMoveMeal");
13
13
  }
14
- /** Machine-readable day key, echoed in every event. */
14
+ get el() { return index.getElement(this); }
15
+ /** Machine-readable day key, echoed in every event. Reflected so a pointer drag can
16
+ * read the target column straight off the element it lands on. */
15
17
  day;
16
18
  /** Human-readable day name shown as the column heading. */
17
19
  dayLabel = '';
@@ -36,6 +38,22 @@ const DaySlot = class {
36
38
  * flicker off mid-column. Counting enter and leave pairs is what makes the state stable.
37
39
  */
38
40
  dragDepth = 0;
41
+ /**
42
+ * Pointer-drag state, used on touch.
43
+ *
44
+ * HTML5 drag-and-drop is a mouse-only API — a touch never produces `dragstart`, so on a
45
+ * phone or tablet the meals simply could not be dragged. Pointer events cover mouse,
46
+ * touch, and pen from one code path, so this runs alongside the native drag rather than
47
+ * replacing it: the native path keeps working where the browser provides it, and this
48
+ * takes over where it does not.
49
+ */
50
+ pointerDrag = null;
51
+ /** The floating copy that follows the finger, appended to the document while dragging. */
52
+ ghost = null;
53
+ /** The panel currently highlighted under the pointer, so it can be un-highlighted. */
54
+ hoveredPanel = null;
55
+ /** Movement in CSS pixels before a press becomes a drag rather than a tap or a scroll. */
56
+ static DRAG_THRESHOLD = 8;
39
57
  /** Fired when the user asks to add a meal to this day. */
40
58
  rpAddMeal;
41
59
  /** Fired when a meal is removed from this day. */
@@ -50,18 +68,34 @@ const DaySlot = class {
50
68
  // replaced before the element upgrades, which @Watch would miss.
51
69
  this.normalized = Array.isArray(this.meals) ? this.meals : [];
52
70
  }
71
+ connectedCallback() {
72
+ /**
73
+ * Every column clears its own highlight when any drag anywhere ends.
74
+ *
75
+ * `dragleave` is not guaranteed: a drop, or a drag abandoned with Escape, can leave a
76
+ * column highlighted with no further event coming to it. Listening for the global end
77
+ * of the gesture is what makes the reset unconditional.
78
+ */
79
+ document.addEventListener('dragend', this.clearDragState);
80
+ document.addEventListener('drop', this.clearDragState);
81
+ }
82
+ disconnectedCallback() {
83
+ // A pointer drag registers listeners on `window` and appends a ghost to the body,
84
+ // both of which would outlive the component if it unmounted mid-drag.
85
+ this.endPointerDrag();
86
+ document.removeEventListener('dragend', this.clearDragState);
87
+ document.removeEventListener('drop', this.clearDragState);
88
+ }
89
+ clearDragState = () => {
90
+ this.dragDepth = 0;
91
+ this.dropActive = false;
92
+ this.draggingId = null;
93
+ };
53
94
  emitMove(id, from, to) {
54
95
  if (!to || to === from)
55
96
  return;
56
97
  this.rpMoveMeal.emit({ id, from, to });
57
98
  }
58
- onMove = (event, meal) => {
59
- const select = event.target;
60
- this.emitMove(meal.id, this.day, select.value);
61
- // The consumer re-renders from its own data; resetting avoids a stale selection
62
- // if that render is delayed.
63
- select.value = '';
64
- };
65
99
  onDragStart = (event, meal) => {
66
100
  this.draggingId = meal.id;
67
101
  // A custom MIME type is what lets dragover distinguish a meal from a dragged file or
@@ -72,11 +106,10 @@ const DaySlot = class {
72
106
  event.dataTransfer?.setData('text/plain', meal.title);
73
107
  if (event.dataTransfer)
74
108
  event.dataTransfer.effectAllowed = 'move';
75
- };
76
- onDragEnd = () => {
77
- this.draggingId = null;
78
- this.dragDepth = 0;
79
- this.dropActive = false;
109
+ // Cleanup is handled by the document-level `dragend`/`drop` listeners registered in
110
+ // `connectedCallback`. The element's own `dragend` cannot be relied on: a successful
111
+ // move re-renders this column, so the source element is gone before the event would
112
+ // have reached it, leaving the card stuck at 40% opacity.
80
113
  };
81
114
  hasMealPayload(event) {
82
115
  return event.dataTransfer?.types.includes('application/x-rp-meal') ?? false;
@@ -103,6 +136,117 @@ const DaySlot = class {
103
136
  if (this.dragDepth === 0)
104
137
  this.dropActive = false;
105
138
  };
139
+ /**
140
+ * Begins tracking a possible pointer drag.
141
+ *
142
+ * Nothing happens until the pointer has moved past the threshold, so a tap still reaches
143
+ * the select and the remove button, and a vertical swipe still scrolls the page.
144
+ */
145
+ onPointerDown = (event, meal) => {
146
+ /**
147
+ * Touch and pen only. A mouse already has HTML5 drag-and-drop, and running both from
148
+ * one gesture makes them fight: this path's `preventDefault` on pointermove — needed
149
+ * to stop a touch scrolling the page — also suppresses the native drag's own feedback,
150
+ * so the card never dimmed and no drag image appeared even though the drop still
151
+ * worked. The native path is left to own the mouse entirely.
152
+ */
153
+ if (event.pointerType === 'mouse')
154
+ return;
155
+ // A press on the select or a button is that control's, not the start of a drag.
156
+ if (event.target.closest('button, select, label, a, rp-select'))
157
+ return;
158
+ this.pointerDrag = {
159
+ id: meal.id,
160
+ title: meal.title,
161
+ pointerId: event.pointerId,
162
+ startX: event.clientX,
163
+ startY: event.clientY,
164
+ started: false,
165
+ };
166
+ window.addEventListener('pointermove', this.onPointerMove, { passive: false });
167
+ window.addEventListener('pointerup', this.onPointerUp);
168
+ window.addEventListener('pointercancel', this.onPointerCancel);
169
+ };
170
+ onPointerMove = (event) => {
171
+ const drag = this.pointerDrag;
172
+ if (!drag || event.pointerId !== drag.pointerId)
173
+ return;
174
+ if (!drag.started) {
175
+ const moved = Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY);
176
+ if (moved < DaySlot.DRAG_THRESHOLD)
177
+ return;
178
+ drag.started = true;
179
+ this.draggingId = drag.id;
180
+ this.createGhost(drag.title);
181
+ }
182
+ // Suppresses the page scroll that a touch-move would otherwise produce.
183
+ event.preventDefault();
184
+ this.moveGhost(event.clientX, event.clientY);
185
+ this.highlightPanelAt(event.clientX, event.clientY);
186
+ };
187
+ onPointerUp = (event) => {
188
+ const drag = this.pointerDrag;
189
+ if (!drag || event.pointerId !== drag.pointerId)
190
+ return;
191
+ const started = drag.started;
192
+ const id = drag.id;
193
+ this.endPointerDrag();
194
+ if (!started)
195
+ return;
196
+ const panel = this.panelAt(event.clientX, event.clientY);
197
+ const to = panel?.getAttribute('day');
198
+ if (to)
199
+ this.emitMove(id, this.day, to);
200
+ };
201
+ onPointerCancel = () => this.endPointerDrag();
202
+ endPointerDrag() {
203
+ this.pointerDrag = null;
204
+ this.draggingId = null;
205
+ this.clearHighlight();
206
+ this.ghost?.remove();
207
+ this.ghost = null;
208
+ window.removeEventListener('pointermove', this.onPointerMove);
209
+ window.removeEventListener('pointerup', this.onPointerUp);
210
+ window.removeEventListener('pointercancel', this.onPointerCancel);
211
+ }
212
+ /** The `rp-day-slot` under a point, found by hit-testing rather than by geometry. */
213
+ panelAt(x, y) {
214
+ // The ghost follows the pointer and would otherwise be the topmost element.
215
+ if (this.ghost)
216
+ this.ghost.style.display = 'none';
217
+ const target = document.elementFromPoint(x, y);
218
+ if (this.ghost)
219
+ this.ghost.style.display = '';
220
+ return target?.closest('rp-day-slot') ?? null;
221
+ }
222
+ highlightPanelAt(x, y) {
223
+ const panel = this.panelAt(x, y);
224
+ if (panel === this.hoveredPanel)
225
+ return;
226
+ this.clearHighlight();
227
+ // The origin column is not a drop target; highlighting it would suggest otherwise.
228
+ if (panel && panel !== this.el) {
229
+ panel.querySelector('.slot')?.classList.add('is-drop-active');
230
+ this.hoveredPanel = panel;
231
+ }
232
+ }
233
+ clearHighlight() {
234
+ this.hoveredPanel?.querySelector('.slot')?.classList.remove('is-drop-active');
235
+ this.hoveredPanel = null;
236
+ }
237
+ createGhost(title) {
238
+ const ghost = document.createElement('div');
239
+ ghost.textContent = title;
240
+ ghost.setAttribute('aria-hidden', 'true');
241
+ ghost.className = 'rp-drag-ghost';
242
+ document.body.append(ghost);
243
+ this.ghost = ghost;
244
+ }
245
+ moveGhost(x, y) {
246
+ if (!this.ghost)
247
+ return;
248
+ this.ghost.style.transform = `translate(${x}px, ${y}px)`;
249
+ }
106
250
  onDrop = (event) => {
107
251
  const payload = event.dataTransfer?.getData('application/x-rp-meal');
108
252
  if (!payload)
@@ -123,9 +267,9 @@ const DaySlot = class {
123
267
  const days = Array.isArray(this.days) ? this.days : [];
124
268
  const labels = this.dayLabels ?? {};
125
269
  const meals = this.normalized;
126
- return (index.h(index.Host, { key: '755cdc190abccb9b0350caf7e4fad05675dd6e0e' }, index.h("section", { key: '927c1e962ce3f918e001965da10bb39b82cab5bc', class: { slot: true, 'is-drop-active': this.dropActive, 'is-empty': meals.length === 0 }, onDragEnter: this.onDragEnter, onDragOver: this.onDragOver, onDragLeave: this.onDragLeave, onDrop: this.onDrop }, index.h("header", { key: '415e9d56f9b190fd291af942c01427cc4b9b66ea', class: "head" }, index.h("h3", { key: 'd0f20de86c70d85da545ec9ec9c57790961b78f0', class: "day" }, this.dayLabel || this.day), index.h("div", { key: '484a1e743a3f251865288f345ead14d87741ff8e', class: "head-right" }, meals.length > 0 && index.h("span", { key: 'ac3324168f0061f4bb173090e21c4b6f2334a168', class: "count" }, meals.length), index.h("button", { key: '5ca123821d1b90cc822bb3036884ce93f8cae19c', type: "button", class: "add", onClick: () => this.rpAddMeal.emit(this.day), "aria-label": `Add a meal to ${this.dayLabel || this.day}` }, index.h("svg", { key: 'e7b09c139cfd3106a83481a1bbb48bf99e82d47c', viewBox: "0 0 24 24", width: "15", height: "15", "aria-hidden": "true" }, index.h("path", { key: '06c62bb2b09a4c0676977411644d15d4217361a8', d: "M12 5v14M5 12h14" }))))), meals.length === 0 ? (index.h("div", { class: "empty" }, index.h("slot", null, index.h("svg", { class: "empty-icon", viewBox: "0 0 24 24", width: "26", height: "26", "aria-hidden": "true" }, index.h("path", { d: "M4 4h16v16H4z", opacity: "0.35" }), index.h("path", { d: "M8 2v4M16 2v4M4 10h16" })), index.h("p", { class: "empty-text" }, "No meals planned")))) : (index.h("ul", { class: "meals" }, meals.map((meal) => (index.h("li", { class: { meal: true, 'is-dragging': this.draggingId === meal.id }, key: meal.id, draggable: true, onDragStart: (event) => this.onDragStart(event, meal), onDragEnd: this.onDragEnd }, index.h("span", { class: "grip", "aria-hidden": "true" }, index.h("svg", { viewBox: "0 0 24 24", width: "12", height: "12" }, index.h("circle", { cx: "9", cy: "6", r: "1.4" }), index.h("circle", { cx: "15", cy: "6", r: "1.4" }), index.h("circle", { cx: "9", cy: "12", r: "1.4" }), index.h("circle", { cx: "15", cy: "12", r: "1.4" }), index.h("circle", { cx: "9", cy: "18", r: "1.4" }), index.h("circle", { cx: "15", cy: "18", r: "1.4" }))), index.h("span", { class: "meal-title" }, meal.title), index.h("div", { class: "meal-actions" }, index.h("label", { class: "move" }, index.h("span", { class: "sr-only" }, `Move ${meal.title} to another day`), index.h("select", { class: "move-select", onChange: (event) => this.onMove(event, meal) }, index.h("option", { value: "" }, "Move\u2026"), days
127
- .filter((day) => day !== this.day)
128
- .map((day) => (index.h("option", { key: day, value: day }, labels[day] ?? day))))), index.h("button", { type: "button", class: "remove", onClick: () => this.rpRemoveMeal.emit({ id: meal.id, day: this.day }), "aria-label": `Remove ${meal.title}` }, index.h("svg", { viewBox: "0 0 24 24", width: "13", height: "13", "aria-hidden": "true" }, index.h("path", { d: "M6 6l12 12M18 6L6 18" }))))))))))));
270
+ return (index.h(index.Host, { key: '47e4ac959151a9e43b8398bcbed2df2af827e9f8' }, index.h("section", { key: 'b08414f465303f8015bc3035e3f12994c1868ac8', class: { slot: true, 'is-drop-active': this.dropActive, 'is-empty': meals.length === 0 }, onDragEnter: this.onDragEnter, onDragOver: this.onDragOver, onDragLeave: this.onDragLeave, onDrop: this.onDrop }, index.h("header", { key: '1b3ab376369ae3339e60740693bcf349ef14a981', class: "head" }, index.h("h3", { key: '077f5818cc37c85110ec831482f6f700ada577dc', class: "day" }, this.dayLabel || this.day), index.h("div", { key: '1fabc2004094d0787d6d734b05d95d825c41c55f', class: "head-right" }, meals.length > 0 && index.h("span", { key: 'af3875556f999563482e8e9ecc833e768515f001', class: "count" }, meals.length), index.h("button", { key: '56f11a2a992f8467d4c876d7ab0771f0f89f31e3', type: "button", class: "add", onClick: () => this.rpAddMeal.emit(this.day), "aria-label": `Add a meal to ${(this.dayLabels ?? {})[this.day] || this.dayLabel || this.day}` }, index.h("svg", { key: 'c27fc88bd1ef85ddac15016e21ca140ffd7d0f82', viewBox: "0 0 24 24", width: "15", height: "15", "aria-hidden": "true" }, index.h("path", { key: 'ecde1e8d37b1c6d2abc9a7edc81ec39d09f79d84', d: "M12 5v14M5 12h14" }))))), meals.length === 0 ? (index.h("div", { class: "empty" }, index.h("slot", null, index.h("svg", { class: "empty-icon", viewBox: "0 0 24 24", width: "26", height: "26", "aria-hidden": "true" }, index.h("path", { d: "M4 4h16v16H4z", opacity: "0.35" }), index.h("path", { d: "M8 2v4M16 2v4M4 10h16" })), index.h("p", { class: "empty-text" }, "No meals planned")))) : (index.h("ul", { class: "meals" }, meals.map((meal) => (index.h("li", { class: { meal: true, 'is-dragging': this.draggingId === meal.id }, key: meal.id, draggable: true, onDragStart: (event) => this.onDragStart(event, meal), onPointerDown: (event) => this.onPointerDown(event, meal) }, index.h("span", { class: "grip", "aria-hidden": "true" }, index.h("svg", { viewBox: "0 0 24 24", width: "12", height: "12" }, index.h("circle", { cx: "9", cy: "6", r: "1.4" }), index.h("circle", { cx: "15", cy: "6", r: "1.4" }), index.h("circle", { cx: "9", cy: "12", r: "1.4" }), index.h("circle", { cx: "15", cy: "12", r: "1.4" }), index.h("circle", { cx: "9", cy: "18", r: "1.4" }), index.h("circle", { cx: "15", cy: "18", r: "1.4" }))), index.h("span", { class: "meal-title" }, meal.title), index.h("div", { class: "meal-actions" }, index.h("rp-select", { class: "move-select", compact: true, label: `Move ${meal.title} to another day`, placeholder: "Move\u2026", options: days
271
+ .filter((day) => day !== this.day)
272
+ .map((day) => ({ value: day, label: labels[day] ?? day })), onRpSelectChange: (event) => this.emitMove(meal.id, this.day, event.detail) }), index.h("button", { type: "button", class: "remove", onClick: () => this.rpRemoveMeal.emit({ id: meal.id, day: this.day }), "aria-label": `Remove ${meal.title}` }, index.h("svg", { viewBox: "0 0 24 24", width: "13", height: "13", "aria-hidden": "true" }, index.h("path", { d: "M6 6l12 12M18 6L6 18" }))))))))))));
129
273
  }
130
274
  };
131
275
  DaySlot.style = rpDaySlotCss();