@flamingo-stack/openframe-frontend-core 0.0.475 → 0.0.476

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 (89) hide show
  1. package/dist/{chunk-5IQXLG4H.js → chunk-2DBCYHR2.js} +2 -2
  2. package/dist/{chunk-A6O75SLQ.js → chunk-6HX7VHJB.js} +2 -2
  3. package/dist/{chunk-DEHW3LYM.cjs → chunk-A6LCWFMD.cjs} +31 -19
  4. package/dist/chunk-A6LCWFMD.cjs.map +1 -0
  5. package/dist/{chunk-YRZZ7HHJ.js → chunk-AE4ZR75U.js} +2 -2
  6. package/dist/{chunk-NJGLBKCR.js → chunk-BKIUYOWZ.js} +4 -4
  7. package/dist/{chunk-7CU7Y3ML.cjs → chunk-BLDESYTK.cjs} +26 -26
  8. package/dist/{chunk-7CU7Y3ML.cjs.map → chunk-BLDESYTK.cjs.map} +1 -1
  9. package/dist/{chunk-BQPZQQPC.js → chunk-EAQ7OR4F.js} +31 -19
  10. package/dist/chunk-EAQ7OR4F.js.map +1 -0
  11. package/dist/{chunk-LM57R7B4.js → chunk-ET7T7IW6.js} +2 -2
  12. package/dist/{chunk-E42Y3ZAL.js → chunk-GPSRQWSQ.js} +2 -2
  13. package/dist/{chunk-WEFPQFUO.js → chunk-K33RUATC.js} +4 -4
  14. package/dist/{chunk-3W6A7LST.cjs → chunk-KZMCU7VV.cjs} +11 -11
  15. package/dist/{chunk-3W6A7LST.cjs.map → chunk-KZMCU7VV.cjs.map} +1 -1
  16. package/dist/{chunk-5ICXBR62.cjs → chunk-LKLU2CQK.cjs} +62 -62
  17. package/dist/{chunk-5ICXBR62.cjs.map → chunk-LKLU2CQK.cjs.map} +1 -1
  18. package/dist/{chunk-PQT3NIDA.js → chunk-LW5H6F2L.js} +4 -4
  19. package/dist/{chunk-QM3DRG5I.cjs → chunk-MNWFO65E.cjs} +9 -9
  20. package/dist/{chunk-QM3DRG5I.cjs.map → chunk-MNWFO65E.cjs.map} +1 -1
  21. package/dist/{chunk-3WBREJMR.js → chunk-MRBIBDHA.js} +4 -4
  22. package/dist/{chunk-E4CNWKZ3.cjs → chunk-O5N2L456.cjs} +7 -7
  23. package/dist/{chunk-E4CNWKZ3.cjs.map → chunk-O5N2L456.cjs.map} +1 -1
  24. package/dist/{chunk-SZNK5Q4A.cjs → chunk-SD443M2O.cjs} +37 -37
  25. package/dist/{chunk-SZNK5Q4A.cjs.map → chunk-SD443M2O.cjs.map} +1 -1
  26. package/dist/{chunk-AIUIIKH2.cjs → chunk-STE3BZNL.cjs} +15 -15
  27. package/dist/{chunk-AIUIIKH2.cjs.map → chunk-STE3BZNL.cjs.map} +1 -1
  28. package/dist/{chunk-HJV4VCEZ.cjs → chunk-TTDO3TQ2.cjs} +5 -5
  29. package/dist/{chunk-HJV4VCEZ.cjs.map → chunk-TTDO3TQ2.cjs.map} +1 -1
  30. package/dist/{chunk-DJAPOTAY.cjs → chunk-V7RX7TBT.cjs} +59 -59
  31. package/dist/{chunk-DJAPOTAY.cjs.map → chunk-V7RX7TBT.cjs.map} +1 -1
  32. package/dist/{chunk-W5UZSGJY.cjs → chunk-VL2BNPJW.cjs} +26 -26
  33. package/dist/{chunk-W5UZSGJY.cjs.map → chunk-VL2BNPJW.cjs.map} +1 -1
  34. package/dist/{chunk-S4VEPOX2.js → chunk-VOUXI6JT.js} +2 -2
  35. package/dist/{chunk-5U7MG3CZ.cjs → chunk-XIU3CWJU.cjs} +31 -31
  36. package/dist/{chunk-5U7MG3CZ.cjs.map → chunk-XIU3CWJU.cjs.map} +1 -1
  37. package/dist/{chunk-R7JJ7PHN.js → chunk-YCKRFXJV.js} +2 -2
  38. package/dist/components/announcement-bar.d.ts +15 -0
  39. package/dist/components/announcement-bar.d.ts.map +1 -1
  40. package/dist/components/case-studies/index.cjs +8 -8
  41. package/dist/components/case-studies/index.js +2 -2
  42. package/dist/components/chat/index.cjs +2 -2
  43. package/dist/components/chat/index.js +1 -1
  44. package/dist/components/contact/index.cjs +3 -3
  45. package/dist/components/contact/index.js +2 -2
  46. package/dist/components/docs/index.cjs +5 -5
  47. package/dist/components/docs/index.js +4 -4
  48. package/dist/components/embeds/index.cjs +3 -3
  49. package/dist/components/embeds/index.js +2 -2
  50. package/dist/components/faq/index.cjs +3 -3
  51. package/dist/components/faq/index.js +2 -2
  52. package/dist/components/features/index.cjs +2 -2
  53. package/dist/components/features/index.js +1 -1
  54. package/dist/components/help-center-pages/index.cjs +20 -20
  55. package/dist/components/help-center-pages/index.js +11 -11
  56. package/dist/components/index.cjs +155 -160
  57. package/dist/components/index.cjs.map +1 -1
  58. package/dist/components/index.js +34 -39
  59. package/dist/components/index.js.map +1 -1
  60. package/dist/components/navigation/index.cjs +2 -2
  61. package/dist/components/navigation/index.js +1 -1
  62. package/dist/components/onboarding-guides/index.cjs +5 -5
  63. package/dist/components/onboarding-guides/index.js +4 -4
  64. package/dist/components/related-content/index.cjs +3 -3
  65. package/dist/components/related-content/index.js +2 -2
  66. package/dist/components/tickets/index.cjs +5 -5
  67. package/dist/components/tickets/index.js +4 -4
  68. package/dist/components/ui/announcement-bar-view.d.ts +47 -26
  69. package/dist/components/ui/announcement-bar-view.d.ts.map +1 -1
  70. package/dist/components/ui/index.cjs +2 -2
  71. package/dist/components/ui/index.js +1 -1
  72. package/dist/index.cjs +2 -2
  73. package/dist/index.js +1 -1
  74. package/package.json +1 -1
  75. package/src/components/announcement-bar.tsx +48 -40
  76. package/src/components/ui/announcement-bar-view.tsx +99 -42
  77. package/dist/chunk-BQPZQQPC.js.map +0 -1
  78. package/dist/chunk-DEHW3LYM.cjs.map +0 -1
  79. /package/dist/{chunk-5IQXLG4H.js.map → chunk-2DBCYHR2.js.map} +0 -0
  80. /package/dist/{chunk-A6O75SLQ.js.map → chunk-6HX7VHJB.js.map} +0 -0
  81. /package/dist/{chunk-YRZZ7HHJ.js.map → chunk-AE4ZR75U.js.map} +0 -0
  82. /package/dist/{chunk-NJGLBKCR.js.map → chunk-BKIUYOWZ.js.map} +0 -0
  83. /package/dist/{chunk-LM57R7B4.js.map → chunk-ET7T7IW6.js.map} +0 -0
  84. /package/dist/{chunk-E42Y3ZAL.js.map → chunk-GPSRQWSQ.js.map} +0 -0
  85. /package/dist/{chunk-WEFPQFUO.js.map → chunk-K33RUATC.js.map} +0 -0
  86. /package/dist/{chunk-PQT3NIDA.js.map → chunk-LW5H6F2L.js.map} +0 -0
  87. /package/dist/{chunk-3WBREJMR.js.map → chunk-MRBIBDHA.js.map} +0 -0
  88. /package/dist/{chunk-S4VEPOX2.js.map → chunk-VOUXI6JT.js.map} +0 -0
  89. /package/dist/{chunk-R7JJ7PHN.js.map → chunk-YCKRFXJV.js.map} +0 -0
@@ -3,85 +3,142 @@
3
3
  import type { CSSProperties, ReactElement, ReactNode } from 'react';
4
4
  import { cn } from '../../utils/cn';
5
5
 
6
+ /**
7
+ * Mirrors `screens.md` in tailwind.config.ts (800px), which is also where the
8
+ * ODS responsive tokens step up (ods-responsive-tokens.css). ONE breakpoint
9
+ * for the whole bar: the `md:` variants below and the `onContentClick` guard
10
+ * must never disagree (they did before — the guard read a stale 768px while
11
+ * the CSS switched at 800px).
12
+ */
13
+ const MD_QUERY = '(min-width: 800px)';
14
+
6
15
  export interface AnnouncementBarViewProps {
7
16
  /**
8
17
  * Leading slot — typically an icon, at content width before the title. Size
9
- * it in the slot: the bar's icon is 16px below `md` (must not exceed the
10
- * 20px title row, Figma 9418-52387) and 24px from `md` up.
18
+ * it in the slot: the bar's icon runs 20px below `md` and 24px from `md` up,
19
+ * and no ODS icon token carries that pair (`--icon-size-icon-size` is 16/24).
11
20
  */
12
21
  startAdornment?: ReactNode;
13
22
  /**
14
- * Bar message. A plain string gets the mockup's text treatment (`text-h4` =
15
- * DM Sans 500, 14/20 below `md` and 18/24 from `md` up), wrapping below `md`
16
- * and truncating to one line from `md` up. Pass a ReactElement to own the
17
- * markup (e.g. bold title + inline description) — mirror that responsive
18
- * wrap/truncate pair in your element.
23
+ * Bar message, always ONE line. A plain string gets the strip's text
24
+ * treatment (`text-h6`, truncating); pass a ReactElement to own the markup
25
+ * (e.g. bold title + inline description truncating as one unit).
19
26
  */
20
27
  title?: string | ReactElement;
21
28
  /**
22
- * Primary CTA. From `md` up it sits inline at content width between the
23
- * title and `endAdornment`; below `md` it moves to its own full-width row
24
- * under the content (Figma 2862-8391) and the bar's height grows to fit.
29
+ * Primary CTA, at content width after the title. Hidden below `md`, where
30
+ * the content row becomes the tap target instead (`onContentClick`) the
31
+ * banner pattern's touch-first tradeoff.
25
32
  */
26
33
  actionBlock?: ReactElement;
27
- /** Trailing slot (e.g. a dismiss button) stays in the top/content row on every breakpoint. */
34
+ /** Trailing slot (e.g. a dismiss button). Outside the tap target, every breakpoint. */
28
35
  endAdornment?: ReactElement;
36
+ /**
37
+ * Below `md` only: fires when the content row is tapped, standing in for the
38
+ * `actionBlock` that is CSS-hidden at that width. No-op from `md` up, where
39
+ * the CTA is visible and owns the interaction.
40
+ */
41
+ onContentClick?: () => void;
42
+ /** Extra classes for the padded content row (e.g. a cursor affordance). */
43
+ contentClassName?: string;
29
44
  /** Surface styling (background, text color, theme scope) is the consumer's — pass it here. */
30
45
  className?: string;
31
46
  style?: CSSProperties;
32
47
  }
33
48
 
34
49
  /**
50
+ * ============================================================================
51
+ * DO NOT REDESIGN THIS BAR. THIS IS THE FINAL, OWNER-APPROVED DESIGN.
52
+ * ============================================================================
53
+ * The 44px single-line strip below is DELIBERATE and has already been
54
+ * regressed and reverted. Read this before you touch a single class:
55
+ *
56
+ * - #1542 (Michael Assraf) RESTORED this exact 44px / text-h6 / compact-CTA
57
+ * design after it drifted.
58
+ * - #1545 "redesigned" it into a 56px, text-h4, stacked-mobile bar.
59
+ * - #1551 REVERTED #1545's UI wholesale, back to THIS.
60
+ *
61
+ * Do NOT:
62
+ * - bump the height (min-h-11 / 44px), the text scale (text-h6), the icon
63
+ * size (20/24px), or the CTA size (compact),
64
+ * - re-introduce a stacked / multi-row / full-width-CTA mobile layout,
65
+ * - "match a new mockup", "improve", "modernize", or "clean up" any of it.
66
+ *
67
+ * This design is the source of truth. A Figma frame is NOT authorization to
68
+ * change it. If you genuinely believe it must change, get Michael's explicit
69
+ * written sign-off on the PR FIRST — otherwise your change WILL be reverted
70
+ * again, exactly like #1545 was. Touch it and you own the revert.
71
+ * ============================================================================
72
+ *
35
73
  * Pure presentational announcement/notification bar. No data fetching,
36
74
  * storage, or navigation — consumers own state and pass content through slots.
37
75
  *
38
- * Layout (Figma 9418-52494 desktop/tablet, 2862-8391 mobile):
39
- * - `md` (800px) and up: ONE row inside a strip with a RESERVED 56px minimum
40
- * height (`md:min-h-14`, the mockup's strip height) held unconditionally,
41
- * so toggling or removing the action never resizes the bar on
42
- * desktop/tablet. Title truncates to one line.
43
- * - Below `md`: the container stacks (`px` 16 / `py` 8 / gap 8). Top row =
44
- * `startAdornment` + wrapping title + `endAdornment`; when an `actionBlock`
45
- * is present it renders as a VISIBLE full-width button on its own second
46
- * row and the bar's height adapts to content (76px with a single-line
47
- * title and CTA per Figma 9418-52387: 8 + 20 + 8 + 32 + 8).
48
- *
49
- * The `actionBlock` element is mounted in both positions (inline `md`-up slot
50
- * and the mobile full-width row); exactly one is `display:none` at any width,
51
- * so keyboard/AT always reach exactly one control.
76
+ * Anatomy follows the announcement-bar industry standard: ONE line of text at
77
+ * 13-14px inside a 44px-tall strip (guides converge on 40-60px with a single
78
+ * sentence; two stacked 18px rows blow past that), ONE compact CTA on the
79
+ * right, and a trailing dismiss slot. Spacing is the ODS responsive tokens,
80
+ * which step at the same 800px as `md`: `l` = 16/24px edge padding, `s` =
81
+ * 8/12px gap, `m` = CTA offset, `xs` = 4/8px.
52
82
  */
53
83
  export function AnnouncementBarView({
54
84
  startAdornment,
55
85
  title,
56
86
  actionBlock,
57
87
  endAdornment,
88
+ onContentClick,
89
+ contentClassName,
58
90
  className,
59
91
  style,
60
92
  }: AnnouncementBarViewProps) {
93
+ const handleContentClick = onContentClick
94
+ ? () => {
95
+ if (!window.matchMedia(MD_QUERY).matches) onContentClick();
96
+ }
97
+ : undefined;
98
+
61
99
  return (
62
- <div
63
- className={cn(
64
- 'flex w-full max-w-full flex-col gap-[var(--spacing-system-s)] px-[var(--spacing-system-l)] py-[var(--spacing-system-s)] md:min-h-14 md:flex-row md:items-center md:py-0',
65
- className,
66
- )}
67
- style={style}
68
- >
69
- {/* Content row: leading icon + title (+ inline CTA from `md`) + trailing
70
- slot. `items-start` below `md` keeps the adornments pinned to the
71
- first text line when the title wraps; `md:items-center` re-centers
72
- everything in the fixed strip. */}
73
- <div className="flex w-full min-w-0 flex-1 items-start gap-[var(--spacing-system-s)] md:w-auto md:items-center">
100
+ <div className={cn('flex w-full max-w-full min-h-11 items-center', className)} style={style}>
101
+ {/* Content row — the tap target below `md`, where the CTA is hidden.
102
+ Its vertical padding never drives the height; the 44px strip does. */}
103
+ <div
104
+ className={cn(
105
+ 'flex min-w-0 flex-1 flex-row items-center gap-[var(--spacing-system-s)] py-[var(--spacing-system-xs)] pl-[var(--spacing-system-l)]',
106
+ contentClassName,
107
+ )}
108
+ onClick={handleContentClick}
109
+ >
74
110
  {startAdornment && <div className="flex shrink-0 items-center">{startAdornment}</div>}
75
111
  {typeof title === 'string' ? (
76
- <p className="mb-0 min-w-0 max-w-full flex-1 break-words text-h4 md:truncate">{title}</p>
112
+ <p className="mb-0 min-w-0 max-w-full flex-1 truncate text-h6">{title}</p>
77
113
  ) : (
78
114
  title != null && <div className="min-w-0 max-w-full flex-1">{title}</div>
79
115
  )}
80
- {actionBlock && <div className="hidden shrink-0 md:flex">{actionBlock}</div>}
81
- {endAdornment && <div className="flex shrink-0 items-center">{endAdornment}</div>}
116
+ {/* Below `md` the CTA is visually replaced by the row-wide tap target,
117
+ but a `display:none` button is unreachable by keyboard and AT. So
118
+ it is only visually hidden there (`sr-only`) and reveals itself on
119
+ focus — the row stays the touch affordance while Tab still reaches
120
+ a real, labelled control. `md:` restores the normal inline CTA.
121
+
122
+ The wrapper stops click propagation: below `md` the CTA lives INSIDE
123
+ the content row (which owns `onContentClick`), so a keyboard/AT
124
+ activation of the revealed button would bubble up and fire the row
125
+ handler too — and both resolve to the same CTA action, opening two
126
+ tabs for `target="_blank"`. Stopping here keeps the row tap target
127
+ for empty space while making the button the sole handler when hit. */}
128
+ {actionBlock && (
129
+ <div
130
+ className="ml-[var(--spacing-system-m)] sr-only shrink-0 focus-within:not-sr-only md:not-sr-only md:flex"
131
+ onClick={(e) => e.stopPropagation()}
132
+ >
133
+ {actionBlock}
134
+ </div>
135
+ )}
82
136
  </div>
83
- {/* Mobile-only action row the CTA stretched to the bar's full width. */}
84
- {actionBlock && <div className="flex w-full md:hidden [&>*]:w-full">{actionBlock}</div>}
137
+ {/* Trailing slot. Its own 32px hit box optically re-centers the glyph
138
+ against the 16/24px left edge. */}
139
+ {endAdornment && (
140
+ <div className="ml-[var(--spacing-system-xs)] mr-[var(--spacing-system-m)] shrink-0">{endAdornment}</div>
141
+ )}
85
142
  </div>
86
143
  );
87
144
  }