@flipdish/ui-library 0.32.1 → 0.34.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 (192) hide show
  1. package/dist/components/atoms/Avatar/components/AvatarLabelGroup.cjs +6 -4
  2. package/dist/components/atoms/Avatar/components/AvatarLabelGroup.cjs.map +1 -1
  3. package/dist/components/atoms/Avatar/components/AvatarLabelGroup.d.ts +7 -1
  4. package/dist/components/atoms/Avatar/components/AvatarLabelGroup.d.ts.map +1 -1
  5. package/dist/components/atoms/Avatar/components/AvatarLabelGroup.js +6 -4
  6. package/dist/components/atoms/Avatar/components/AvatarLabelGroup.js.map +1 -1
  7. package/dist/components/atoms/Badge/badge.types.cjs.map +1 -1
  8. package/dist/components/atoms/Badge/badge.types.d.ts +2 -1
  9. package/dist/components/atoms/Badge/badge.types.d.ts.map +1 -1
  10. package/dist/components/atoms/Badge/badge.types.js.map +1 -1
  11. package/dist/components/atoms/Badge/index.cjs +2 -1
  12. package/dist/components/atoms/Badge/index.cjs.map +1 -1
  13. package/dist/components/atoms/Badge/index.d.ts.map +1 -1
  14. package/dist/components/atoms/Badge/index.js +2 -1
  15. package/dist/components/atoms/Badge/index.js.map +1 -1
  16. package/dist/components/atoms/Card/index.cjs +28 -0
  17. package/dist/components/atoms/Card/index.cjs.map +1 -0
  18. package/dist/components/atoms/Card/index.d.ts +20 -0
  19. package/dist/components/atoms/Card/index.d.ts.map +1 -0
  20. package/dist/components/atoms/Card/index.js +26 -0
  21. package/dist/components/atoms/Card/index.js.map +1 -0
  22. package/dist/components/atoms/CopyButton/index.cjs +27 -0
  23. package/dist/components/atoms/CopyButton/index.cjs.map +1 -0
  24. package/dist/components/atoms/CopyButton/index.d.ts +28 -0
  25. package/dist/components/atoms/CopyButton/index.d.ts.map +1 -0
  26. package/dist/components/atoms/CopyButton/index.js +25 -0
  27. package/dist/components/atoms/CopyButton/index.js.map +1 -0
  28. package/dist/components/atoms/Flag/flag.types.d.ts +6 -0
  29. package/dist/components/atoms/Flag/flag.types.d.ts.map +1 -0
  30. package/dist/components/atoms/Flag/flag.utils.cjs +45 -0
  31. package/dist/components/atoms/Flag/flag.utils.cjs.map +1 -0
  32. package/dist/components/atoms/Flag/flag.utils.d.ts +15 -0
  33. package/dist/components/atoms/Flag/flag.utils.d.ts.map +1 -0
  34. package/dist/components/atoms/Flag/flag.utils.js +42 -0
  35. package/dist/components/atoms/Flag/flag.utils.js.map +1 -0
  36. package/dist/components/atoms/Flag/index.cjs +47 -0
  37. package/dist/components/atoms/Flag/index.cjs.map +1 -0
  38. package/dist/components/atoms/Flag/index.d.ts +27 -0
  39. package/dist/components/atoms/Flag/index.d.ts.map +1 -0
  40. package/dist/components/atoms/Flag/index.js +45 -0
  41. package/dist/components/atoms/Flag/index.js.map +1 -0
  42. package/dist/components/atoms/SearchInput/index.cjs +32 -0
  43. package/dist/components/atoms/SearchInput/index.cjs.map +1 -0
  44. package/dist/components/atoms/SearchInput/index.d.ts +40 -0
  45. package/dist/components/atoms/SearchInput/index.d.ts.map +1 -0
  46. package/dist/components/atoms/SearchInput/index.js +30 -0
  47. package/dist/components/atoms/SearchInput/index.js.map +1 -0
  48. package/dist/components/molecules/CodeSnippet/codeSnippet.utils.cjs +73 -0
  49. package/dist/components/molecules/CodeSnippet/codeSnippet.utils.cjs.map +1 -1
  50. package/dist/components/molecules/CodeSnippet/codeSnippet.utils.d.ts +48 -0
  51. package/dist/components/molecules/CodeSnippet/codeSnippet.utils.d.ts.map +1 -1
  52. package/dist/components/molecules/CodeSnippet/codeSnippet.utils.js +70 -1
  53. package/dist/components/molecules/CodeSnippet/codeSnippet.utils.js.map +1 -1
  54. package/dist/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.cjs +24 -2
  55. package/dist/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.cjs.map +1 -1
  56. package/dist/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.d.ts +2 -1
  57. package/dist/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.d.ts.map +1 -1
  58. package/dist/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.js +25 -3
  59. package/dist/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.js.map +1 -1
  60. package/dist/components/molecules/CodeSnippet/index.cjs +7 -25
  61. package/dist/components/molecules/CodeSnippet/index.cjs.map +1 -1
  62. package/dist/components/molecules/CodeSnippet/index.d.ts +8 -4
  63. package/dist/components/molecules/CodeSnippet/index.d.ts.map +1 -1
  64. package/dist/components/molecules/CodeSnippet/index.js +8 -26
  65. package/dist/components/molecules/CodeSnippet/index.js.map +1 -1
  66. package/dist/components/molecules/DetailList/detailList.types.d.ts +15 -0
  67. package/dist/components/molecules/DetailList/detailList.types.d.ts.map +1 -0
  68. package/dist/components/molecules/DetailList/index.cjs +32 -0
  69. package/dist/components/molecules/DetailList/index.cjs.map +1 -0
  70. package/dist/components/molecules/DetailList/index.d.ts +26 -0
  71. package/dist/components/molecules/DetailList/index.d.ts.map +1 -0
  72. package/dist/components/molecules/DetailList/index.js +30 -0
  73. package/dist/components/molecules/DetailList/index.js.map +1 -0
  74. package/dist/components/molecules/RadioGroup/components/RadioGroupAvatarCard.cjs +43 -0
  75. package/dist/components/molecules/RadioGroup/components/RadioGroupAvatarCard.cjs.map +1 -0
  76. package/dist/components/molecules/RadioGroup/components/RadioGroupAvatarCard.d.ts +24 -0
  77. package/dist/components/molecules/RadioGroup/components/RadioGroupAvatarCard.d.ts.map +1 -0
  78. package/dist/components/molecules/RadioGroup/components/RadioGroupAvatarCard.js +41 -0
  79. package/dist/components/molecules/RadioGroup/components/RadioGroupAvatarCard.js.map +1 -0
  80. package/dist/components/molecules/RadioGroup/index.cjs +2 -0
  81. package/dist/components/molecules/RadioGroup/index.cjs.map +1 -1
  82. package/dist/components/molecules/RadioGroup/index.d.ts +2 -0
  83. package/dist/components/molecules/RadioGroup/index.d.ts.map +1 -1
  84. package/dist/components/molecules/RadioGroup/index.js +1 -0
  85. package/dist/components/molecules/RadioGroup/index.js.map +1 -1
  86. package/dist/components/molecules/RadioGroup/radioGroup.types.d.ts +17 -1
  87. package/dist/components/molecules/RadioGroup/radioGroup.types.d.ts.map +1 -1
  88. package/dist/components/organisms/ApplicationHeader/applicationHeader.types.d.ts +8 -2
  89. package/dist/components/organisms/ApplicationHeader/applicationHeader.types.d.ts.map +1 -1
  90. package/dist/components/organisms/ApplicationHeader/components/AvatarButton.cjs +4 -1
  91. package/dist/components/organisms/ApplicationHeader/components/AvatarButton.cjs.map +1 -1
  92. package/dist/components/organisms/ApplicationHeader/components/AvatarButton.d.ts +2 -1
  93. package/dist/components/organisms/ApplicationHeader/components/AvatarButton.d.ts.map +1 -1
  94. package/dist/components/organisms/ApplicationHeader/components/AvatarButton.js +4 -1
  95. package/dist/components/organisms/ApplicationHeader/components/AvatarButton.js.map +1 -1
  96. package/dist/components/organisms/ApplicationHeader/index.cjs +1 -1
  97. package/dist/components/organisms/ApplicationHeader/index.cjs.map +1 -1
  98. package/dist/components/organisms/ApplicationHeader/index.d.ts.map +1 -1
  99. package/dist/components/organisms/ApplicationHeader/index.js +1 -1
  100. package/dist/components/organisms/ApplicationHeader/index.js.map +1 -1
  101. package/dist/components/organisms/Calendar/calendar.utils.cjs +35 -0
  102. package/dist/components/organisms/Calendar/calendar.utils.cjs.map +1 -1
  103. package/dist/components/organisms/Calendar/calendar.utils.d.ts +29 -0
  104. package/dist/components/organisms/Calendar/calendar.utils.d.ts.map +1 -1
  105. package/dist/components/organisms/Calendar/calendar.utils.js +36 -2
  106. package/dist/components/organisms/Calendar/calendar.utils.js.map +1 -1
  107. package/dist/components/organisms/Calendar/hooks/useCalendarClock.cjs +30 -0
  108. package/dist/components/organisms/Calendar/hooks/useCalendarClock.cjs.map +1 -0
  109. package/dist/components/organisms/Calendar/hooks/useCalendarClock.d.ts +12 -0
  110. package/dist/components/organisms/Calendar/hooks/useCalendarClock.d.ts.map +1 -0
  111. package/dist/components/organisms/Calendar/hooks/useCalendarClock.js +28 -0
  112. package/dist/components/organisms/Calendar/hooks/useCalendarClock.js.map +1 -0
  113. package/dist/components/organisms/Calendar/index.cjs +13 -42
  114. package/dist/components/organisms/Calendar/index.cjs.map +1 -1
  115. package/dist/components/organisms/Calendar/index.d.ts.map +1 -1
  116. package/dist/components/organisms/Calendar/index.js +15 -44
  117. package/dist/components/organisms/Calendar/index.js.map +1 -1
  118. package/dist/components/organisms/HeaderNavigation/index.cjs +2 -3
  119. package/dist/components/organisms/HeaderNavigation/index.cjs.map +1 -1
  120. package/dist/components/organisms/HeaderNavigation/index.d.ts.map +1 -1
  121. package/dist/components/organisms/HeaderNavigation/index.js +2 -3
  122. package/dist/components/organisms/HeaderNavigation/index.js.map +1 -1
  123. package/dist/components/organisms/SidePanel/components/SidePanelContent.cjs +3 -1
  124. package/dist/components/organisms/SidePanel/components/SidePanelContent.cjs.map +1 -1
  125. package/dist/components/organisms/SidePanel/components/SidePanelContent.d.ts.map +1 -1
  126. package/dist/components/organisms/SidePanel/components/SidePanelContent.js +3 -1
  127. package/dist/components/organisms/SidePanel/components/SidePanelContent.js.map +1 -1
  128. package/dist/components/organisms/SidePanel/components/SidePanelFooter.cjs +3 -3
  129. package/dist/components/organisms/SidePanel/components/SidePanelFooter.cjs.map +1 -1
  130. package/dist/components/organisms/SidePanel/components/SidePanelFooter.d.ts +7 -2
  131. package/dist/components/organisms/SidePanel/components/SidePanelFooter.d.ts.map +1 -1
  132. package/dist/components/organisms/SidePanel/components/SidePanelFooter.js +3 -3
  133. package/dist/components/organisms/SidePanel/components/SidePanelFooter.js.map +1 -1
  134. package/dist/components/organisms/SidePanel/components/SidePanelHeader.cjs +7 -3
  135. package/dist/components/organisms/SidePanel/components/SidePanelHeader.cjs.map +1 -1
  136. package/dist/components/organisms/SidePanel/components/SidePanelHeader.d.ts +6 -2
  137. package/dist/components/organisms/SidePanel/components/SidePanelHeader.d.ts.map +1 -1
  138. package/dist/components/organisms/SidePanel/components/SidePanelHeader.js +7 -3
  139. package/dist/components/organisms/SidePanel/components/SidePanelHeader.js.map +1 -1
  140. package/dist/components/organisms/SidePanel/components/SidePanelRegion.cjs +8 -3
  141. package/dist/components/organisms/SidePanel/components/SidePanelRegion.cjs.map +1 -1
  142. package/dist/components/organisms/SidePanel/components/SidePanelRegion.d.ts +2 -1
  143. package/dist/components/organisms/SidePanel/components/SidePanelRegion.d.ts.map +1 -1
  144. package/dist/components/organisms/SidePanel/components/SidePanelRegion.js +8 -3
  145. package/dist/components/organisms/SidePanel/components/SidePanelRegion.js.map +1 -1
  146. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.cjs +12 -1
  147. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.cjs.map +1 -1
  148. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.d.ts +3 -1
  149. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.d.ts.map +1 -1
  150. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.js +13 -2
  151. package/dist/components/organisms/SidePanel/hooks/usePanelFocus.js.map +1 -1
  152. package/dist/components/organisms/SidePanel/index.cjs +2 -2
  153. package/dist/components/organisms/SidePanel/index.cjs.map +1 -1
  154. package/dist/components/organisms/SidePanel/index.d.ts +3 -1
  155. package/dist/components/organisms/SidePanel/index.d.ts.map +1 -1
  156. package/dist/components/organisms/SidePanel/index.js +2 -2
  157. package/dist/components/organisms/SidePanel/index.js.map +1 -1
  158. package/dist/components/organisms/SidebarNavigation/components/NavAccountCard.cjs +9 -2
  159. package/dist/components/organisms/SidebarNavigation/components/NavAccountCard.cjs.map +1 -1
  160. package/dist/components/organisms/SidebarNavigation/components/NavAccountCard.d.ts +12 -1
  161. package/dist/components/organisms/SidebarNavigation/components/NavAccountCard.d.ts.map +1 -1
  162. package/dist/components/organisms/SidebarNavigation/components/NavAccountCard.js +9 -2
  163. package/dist/components/organisms/SidebarNavigation/components/NavAccountCard.js.map +1 -1
  164. package/dist/components/organisms/SidebarNavigation/components/NavItem.cjs +10 -4
  165. package/dist/components/organisms/SidebarNavigation/components/NavItem.cjs.map +1 -1
  166. package/dist/components/organisms/SidebarNavigation/components/NavItem.d.ts +12 -1
  167. package/dist/components/organisms/SidebarNavigation/components/NavItem.d.ts.map +1 -1
  168. package/dist/components/organisms/SidebarNavigation/components/NavItem.js +10 -4
  169. package/dist/components/organisms/SidebarNavigation/components/NavItem.js.map +1 -1
  170. package/dist/components/organisms/SidebarNavigation/index.cjs +36 -11
  171. package/dist/components/organisms/SidebarNavigation/index.cjs.map +1 -1
  172. package/dist/components/organisms/SidebarNavigation/index.d.ts.map +1 -1
  173. package/dist/components/organisms/SidebarNavigation/index.js +38 -13
  174. package/dist/components/organisms/SidebarNavigation/index.js.map +1 -1
  175. package/dist/native/components/atoms/Card/index.d.ts +12 -0
  176. package/dist/native/components/atoms/CopyButton/index.d.ts +12 -0
  177. package/dist/native/components/atoms/Flag/index.d.ts +12 -0
  178. package/dist/native/components/atoms/SearchInput/index.d.ts +12 -0
  179. package/dist/native/components/molecules/DetailList/index.d.ts +12 -0
  180. package/dist/utilities/renderUtils/index.cjs +21 -0
  181. package/dist/utilities/renderUtils/index.cjs.map +1 -1
  182. package/dist/utilities/renderUtils/index.d.ts +10 -0
  183. package/dist/utilities/renderUtils/index.d.ts.map +1 -1
  184. package/dist/utilities/renderUtils/index.js +21 -1
  185. package/dist/utilities/renderUtils/index.js.map +1 -1
  186. package/package.json +2 -1
  187. package/dist/components/organisms/SidebarNavigation/components/NavButton.cjs +0 -32
  188. package/dist/components/organisms/SidebarNavigation/components/NavButton.cjs.map +0 -1
  189. package/dist/components/organisms/SidebarNavigation/components/NavButton.d.ts +0 -36
  190. package/dist/components/organisms/SidebarNavigation/components/NavButton.d.ts.map +0 -1
  191. package/dist/components/organisms/SidebarNavigation/components/NavButton.js +0 -30
  192. package/dist/components/organisms/SidebarNavigation/components/NavButton.js.map +0 -1
@@ -0,0 +1,42 @@
1
+ import { isProductionBuild } from '@flipdish/ui-library/utilities/renderUtils';
2
+
3
+ const resolvers = new Map();
4
+ const warnedCodes = new Set();
5
+ /**
6
+ * Resolves a country's name from its ISO 3166-1 alpha-2 code, for the flag's default accessible name.
7
+ * @param code The country code, as `Flag` receives it.
8
+ * @param locale BCP 47 tag the name is written in; the app's locale, so server and client agree.
9
+ * @returns The region name in that locale, or the code itself where `Intl.DisplayNames` is missing or rejects the code or locale.
10
+ */
11
+ const getCountryName = (code, locale = 'en') => {
12
+ // Built once per locale; `Intl.DisplayNames` is missing from some older runtimes, where the code stands in.
13
+ let resolver = resolvers.get(locale);
14
+ if (resolver === undefined) {
15
+ try {
16
+ resolver = typeof Intl.DisplayNames === 'function' ? new Intl.DisplayNames([locale], { type: 'region' }) : null;
17
+ }
18
+ catch {
19
+ resolver = null;
20
+ }
21
+ resolvers.set(locale, resolver);
22
+ }
23
+ try {
24
+ return resolver?.of(code) ?? code;
25
+ }
26
+ catch {
27
+ return code;
28
+ }
29
+ };
30
+ /**
31
+ * Warns once per unknown country code outside production, so a bad code is visible in development without flooding the console.
32
+ * @param code The code no flag exists for.
33
+ */
34
+ const warnUnknownCountryOnce = (code) => {
35
+ if (isProductionBuild() || warnedCodes.has(code))
36
+ return;
37
+ warnedCodes.add(code);
38
+ console.warn(`Flag: no flag for country code "${code}".`);
39
+ };
40
+
41
+ export { getCountryName, warnUnknownCountryOnce };
42
+ //# sourceMappingURL=flag.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flag.utils.js","sources":["../../../../src/components/atoms/Flag/flag.utils.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoC;AAC7D,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU;AAErC;;;;;AAKG;AACI,MAAM,cAAc,GAAG,CAAC,IAAY,EAAE,MAAM,GAAG,IAAI,KAAY;;IAEpE,IAAI,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC;AACpC,IAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;AAC1B,QAAA,IAAI;AACF,YAAA,QAAQ,GAAG,OAAO,IAAI,CAAC,YAAY,KAAK,UAAU,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;QACjH;AAAE,QAAA,MAAM;YACN,QAAQ,GAAG,IAAI;QACjB;AACA,QAAA,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;IACjC;AACA,IAAA,IAAI;QACF,OAAO,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI;IACnC;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,IAAI;IACb;AACF;AAEA;;;AAGG;AACI,MAAM,sBAAsB,GAAG,CAAC,IAAY,KAAU;IAC3D,IAAI,iBAAiB,EAAE,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE;AAClD,IAAA,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AACrB,IAAA,OAAO,CAAC,IAAI,CAAC,mCAAmC,IAAI,CAAA,EAAA,CAAI,CAAC;AAC3D;;"}
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var cx = require('@flipdish/ui-library/utilities/cx');
5
+ var testIdUtils = require('@flipdish/ui-library/utilities/testIdUtils');
6
+ var React = require('react');
7
+ var flag_utils = require('./flag.utils.cjs');
8
+
9
+ const toFlagSvg = (set) => {
10
+ const FlagSvg = ({ code, ...props }) => {
11
+ const Svg = set[code];
12
+ if (!Svg) {
13
+ flag_utils.warnUnknownCountryOnce(code);
14
+ return null;
15
+ }
16
+ return jsxRuntime.jsx(Svg, { ...props });
17
+ };
18
+ return { default: FlagSvg };
19
+ };
20
+ // Each set is every country in one ~53 KB gzip module, so it loads on the first flag of that shape rather than with every importer of `Flag`.
21
+ const FLAG_SVGS = {
22
+ round: React.lazy(() => import('country-flag-icons/react/1x1').then((flags) => toFlagSvg(flags))),
23
+ rectangle: React.lazy(() => import('country-flag-icons/react/3x2').then((flags) => toFlagSvg(flags))),
24
+ };
25
+ // A rectangle keeps the art's 3:2 ratio at the same height as the round flag.
26
+ const SIZES = {
27
+ round: { xs: 'size-4', sm: 'size-5', md: 'size-6', lg: 'size-8' },
28
+ rectangle: { xs: 'h-4 w-6', sm: 'h-5 w-7.5', md: 'h-6 w-9', lg: 'h-8 w-12' },
29
+ };
30
+ /**
31
+ * A country's flag from its ISO code, round for inline use beside a label or rectangular where
32
+ * the full flag matters. Each shape is one bundled set from `country-flag-icons` that loads on
33
+ * its first use, so a page costs nothing until it shows a flag and the same after that however
34
+ * many countries it shows.
35
+ *
36
+ * @summary country flag from an ISO country code
37
+ */
38
+ const Flag = ({ code, size = 'sm', shape = 'round', label, locale, className, 'data-testid': dataTestId, ...props }) => {
39
+ const flagTestId = testIdUtils.useResolvedTestId({ testId: dataTestId, segment: 'flag', rootName: 'flag' });
40
+ const name = label ?? flag_utils.getCountryName(code, locale);
41
+ const isDecorative = name === '';
42
+ const FlagSvg = FLAG_SVGS[shape];
43
+ return (jsxRuntime.jsx(React.Suspense, { fallback: null, children: jsxRuntime.jsx(FlagSvg, { ...props, code: code, "data-testid": flagTestId, role: isDecorative ? undefined : 'img', "aria-label": isDecorative ? undefined : name, "aria-hidden": isDecorative || undefined, title: isDecorative ? undefined : name, className: cx.cx('shrink-0 overflow-hidden', shape === 'round' && 'rounded-full', SIZES[shape][size], className) }) }));
44
+ };
45
+
46
+ exports.Flag = Flag;
47
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/atoms/Flag/index.tsx"],"sourcesContent":[null],"names":["warnUnknownCountryOnce","_jsx","lazy","useResolvedTestId","getCountryName","Suspense","cx"],"mappings":";;;;;;;;AAeA,MAAM,SAAS,GAAG,CAAC,GAAY,KAAI;IACjC,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,KAAK,EAAmC,KAAI;AACtE,QAAA,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,GAAG,EAAE;YACRA,iCAAsB,CAAC,IAAI,CAAC;AAC5B,YAAA,OAAO,IAAI;QACb;AACA,QAAA,OAAOC,cAAA,CAAC,GAAG,EAAA,EAAA,GAAK,KAAK,GAAI;AAC3B,IAAA,CAAC;AACD,IAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE;AAC7B,CAAC;AAED;AACA,MAAM,SAAS,GAAG;IAChB,KAAK,EAAEC,UAAI,CAAC,MAAM,OAAO,8BAA8B,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,KAAgB,CAAC,CAAC,CAAC;IACtG,SAAS,EAAEA,UAAI,CAAC,MAAM,OAAO,8BAA8B,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,KAAgB,CAAC,CAAC,CAAC;CAC3G;AAED;AACA,MAAM,KAAK,GAAgD;AACzD,IAAA,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE;AACjE,IAAA,SAAS,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE;CAC7E;AAiBD;;;;;;;AAOG;AACI,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAa,KAAI;AACvI,IAAA,MAAM,UAAU,GAAGC,6BAAiB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC/F,MAAM,IAAI,GAAG,KAAK,IAAIC,yBAAc,CAAC,IAAI,EAAE,MAAM,CAAC;AAClD,IAAA,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE;AAChC,IAAA,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC;AAEhC,IAAA,QACEH,cAAA,CAACI,cAAQ,EAAA,EAAC,QAAQ,EAAE,IAAI,EAAA,QAAA,EACtBJ,cAAA,CAAC,OAAO,OACF,KAAK,EACT,IAAI,EAAE,IAAI,iBACG,UAAU,EACvB,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,KAAK,EAAA,YAAA,EAC1B,YAAY,GAAG,SAAS,GAAG,IAAI,EAAA,aAAA,EAC9B,YAAY,IAAI,SAAS,EACtC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,EACtC,SAAS,EAAEK,KAAE,CAAC,0BAA0B,EAAE,KAAK,KAAK,OAAO,IAAI,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EAAA,CAC7G,EAAA,CACO;AAEf;;"}
@@ -0,0 +1,27 @@
1
+ import type { SVGProps } from 'react';
2
+ import type { CountryCode, FlagShape, FlagSize } from './flag.types';
3
+ export type { CountryCode, FlagShape, FlagSize } from './flag.types';
4
+ export interface FlagProps extends Omit<SVGProps<SVGSVGElement>, 'children'> {
5
+ /** ISO 3166-1 alpha-2 code of the country to show. */
6
+ code: CountryCode;
7
+ /** Height: `xs` 16px, `sm` 20px, `md` 24px, `lg` 32px. A rectangle is 3:2, so wider than tall. */
8
+ size?: FlagSize;
9
+ /** `round` clips the square art to a circle; `rectangle` shows the 3:2 flag. */
10
+ shape?: FlagShape;
11
+ /** Accessible name. Defaults to the country's name in `locale`; pass `''` to hide the flag from assistive technology when visible text beside it already names the country. */
12
+ label?: string;
13
+ /** BCP 47 tag the default name is written in. Pass the app's locale rather than reading the browser's, so server and client render the same name. */
14
+ locale?: string;
15
+ /** Overrides the `data-testid` (defaults to `fd-flag`). */
16
+ 'data-testid'?: string;
17
+ }
18
+ /**
19
+ * A country's flag from its ISO code, round for inline use beside a label or rectangular where
20
+ * the full flag matters. Each shape is one bundled set from `country-flag-icons` that loads on
21
+ * its first use, so a page costs nothing until it shows a flag and the same after that however
22
+ * many countries it shows.
23
+ *
24
+ * @summary country flag from an ISO country code
25
+ */
26
+ export declare const Flag: ({ code, size, shape, label, locale, className, "data-testid": dataTestId, ...props }: FlagProps) => import("react").JSX.Element;
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/Flag/index.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAgB,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGrE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AA8BrE,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,UAAU,CAAC;IAC1E,sDAAsD;IACtD,IAAI,EAAE,WAAW,CAAC;IAClB,kGAAkG;IAClG,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,gFAAgF;IAChF,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+KAA+K;IAC/K,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qJAAqJ;IACrJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,GAAI,sFAAuG,SAAS,gCAoBpI,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { cx } from '@flipdish/ui-library/utilities/cx';
3
+ import { useResolvedTestId } from '@flipdish/ui-library/utilities/testIdUtils';
4
+ import { lazy, Suspense } from 'react';
5
+ import { warnUnknownCountryOnce, getCountryName } from './flag.utils.js';
6
+
7
+ const toFlagSvg = (set) => {
8
+ const FlagSvg = ({ code, ...props }) => {
9
+ const Svg = set[code];
10
+ if (!Svg) {
11
+ warnUnknownCountryOnce(code);
12
+ return null;
13
+ }
14
+ return jsx(Svg, { ...props });
15
+ };
16
+ return { default: FlagSvg };
17
+ };
18
+ // Each set is every country in one ~53 KB gzip module, so it loads on the first flag of that shape rather than with every importer of `Flag`.
19
+ const FLAG_SVGS = {
20
+ round: lazy(() => import('country-flag-icons/react/1x1').then((flags) => toFlagSvg(flags))),
21
+ rectangle: lazy(() => import('country-flag-icons/react/3x2').then((flags) => toFlagSvg(flags))),
22
+ };
23
+ // A rectangle keeps the art's 3:2 ratio at the same height as the round flag.
24
+ const SIZES = {
25
+ round: { xs: 'size-4', sm: 'size-5', md: 'size-6', lg: 'size-8' },
26
+ rectangle: { xs: 'h-4 w-6', sm: 'h-5 w-7.5', md: 'h-6 w-9', lg: 'h-8 w-12' },
27
+ };
28
+ /**
29
+ * A country's flag from its ISO code, round for inline use beside a label or rectangular where
30
+ * the full flag matters. Each shape is one bundled set from `country-flag-icons` that loads on
31
+ * its first use, so a page costs nothing until it shows a flag and the same after that however
32
+ * many countries it shows.
33
+ *
34
+ * @summary country flag from an ISO country code
35
+ */
36
+ const Flag = ({ code, size = 'sm', shape = 'round', label, locale, className, 'data-testid': dataTestId, ...props }) => {
37
+ const flagTestId = useResolvedTestId({ testId: dataTestId, segment: 'flag', rootName: 'flag' });
38
+ const name = label ?? getCountryName(code, locale);
39
+ const isDecorative = name === '';
40
+ const FlagSvg = FLAG_SVGS[shape];
41
+ return (jsx(Suspense, { fallback: null, children: jsx(FlagSvg, { ...props, code: code, "data-testid": flagTestId, role: isDecorative ? undefined : 'img', "aria-label": isDecorative ? undefined : name, "aria-hidden": isDecorative || undefined, title: isDecorative ? undefined : name, className: cx('shrink-0 overflow-hidden', shape === 'round' && 'rounded-full', SIZES[shape][size], className) }) }));
42
+ };
43
+
44
+ export { Flag };
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/atoms/Flag/index.tsx"],"sourcesContent":[null],"names":["_jsx"],"mappings":";;;;;;AAeA,MAAM,SAAS,GAAG,CAAC,GAAY,KAAI;IACjC,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,KAAK,EAAmC,KAAI;AACtE,QAAA,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,GAAG,EAAE;YACR,sBAAsB,CAAC,IAAI,CAAC;AAC5B,YAAA,OAAO,IAAI;QACb;AACA,QAAA,OAAOA,GAAA,CAAC,GAAG,EAAA,EAAA,GAAK,KAAK,GAAI;AAC3B,IAAA,CAAC;AACD,IAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE;AAC7B,CAAC;AAED;AACA,MAAM,SAAS,GAAG;IAChB,KAAK,EAAE,IAAI,CAAC,MAAM,OAAO,8BAA8B,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,KAAgB,CAAC,CAAC,CAAC;IACtG,SAAS,EAAE,IAAI,CAAC,MAAM,OAAO,8BAA8B,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,KAAgB,CAAC,CAAC,CAAC;CAC3G;AAED;AACA,MAAM,KAAK,GAAgD;AACzD,IAAA,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE;AACjE,IAAA,SAAS,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE;CAC7E;AAiBD;;;;;;;AAOG;AACI,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,KAAK,EAAa,KAAI;AACvI,IAAA,MAAM,UAAU,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC/F,MAAM,IAAI,GAAG,KAAK,IAAI,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC;AAClD,IAAA,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE;AAChC,IAAA,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC;AAEhC,IAAA,QACEA,GAAA,CAAC,QAAQ,EAAA,EAAC,QAAQ,EAAE,IAAI,EAAA,QAAA,EACtBA,GAAA,CAAC,OAAO,OACF,KAAK,EACT,IAAI,EAAE,IAAI,iBACG,UAAU,EACvB,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,KAAK,EAAA,YAAA,EAC1B,YAAY,GAAG,SAAS,GAAG,IAAI,EAAA,aAAA,EAC9B,YAAY,IAAI,SAAS,EACtC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,EACtC,SAAS,EAAE,EAAE,CAAC,0BAA0B,EAAE,KAAK,KAAK,OAAO,IAAI,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,EAAA,CAC7G,EAAA,CACO;AAEf;;"}
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var uiIcons = require('@flipdish/ui-icons');
5
+ var Input = require('@flipdish/ui-library/components/atoms/Input');
6
+ var cx = require('@flipdish/ui-library/utilities/cx');
7
+ var testIdUtils = require('@flipdish/ui-library/utilities/testIdUtils');
8
+ var reactAriaComponents = require('react-aria-components');
9
+ var useHotkeyHint = require('../../../hooks/__internal__/useHotkeyHint/useHotkeyHint.cjs');
10
+
11
+ const sizes = cx.sortCx({
12
+ sm: { input: 'py-2 pr-9 pl-9 text-sm', icon: 'left-3 size-4 stroke-[2.25px]', clear: 'right-2', shortcut: 'pr-1.5' },
13
+ md: { input: 'py-2 pr-9 pl-10 text-md', icon: 'left-3 size-5', clear: 'right-2', shortcut: 'pr-2' },
14
+ lg: { input: 'py-2.5 pr-9.5 pl-10.5 text-md', icon: 'left-3.5 size-5', clear: 'right-2.5', shortcut: 'pr-2.5' },
15
+ });
16
+ /**
17
+ * A search box with a magnifier, a clear button once it holds text, and Escape to clear. Use it
18
+ * wherever typing filters a list or table; for a field that collects a value, use `Input`.
19
+ *
20
+ * @summary search box that filters as you type and clears in one press
21
+ */
22
+ const SearchInput = ({ label, hint, placeholder, size = 'md', clearLabel = 'Clear search', shortcut, className, wrapperClassName, inputClassName, ref, 'data-testid': dataTestId, ...props }) => {
23
+ const inputTestId = testIdUtils.useResolvedTestId({ testId: dataTestId, segment: 'search-input', rootName: 'search-input' });
24
+ const shortcutLabel = useHotkeyHint.useHotkeyHint(shortcut === true ? 'mod+k' : shortcut || null);
25
+ return (jsxRuntime.jsx(reactAriaComponents.SearchField, { "aria-label": label ? undefined : placeholder, ...props, className: cx.cx('group/search flex h-max w-full flex-col items-start gap-1.5', className), children: ({ isInvalid, isDisabled }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [label && jsxRuntime.jsx(Input.Label, { isInvalid: isInvalid, children: label }), jsxRuntime.jsxs(reactAriaComponents.Group, { isDisabled: isDisabled, isInvalid: isInvalid, className: ({ isFocusWithin }) => cx.cx('relative flex w-full items-center rounded-lg bg-primary shadow-xs ring-1 ring-primary transition-shadow duration-100 ease-linear ring-inset', isFocusWithin && !isDisabled && 'ring-2 ring-brand', isDisabled && 'cursor-not-allowed opacity-50', isInvalid && 'ring-error_subtle', isInvalid && isFocusWithin && 'ring-2 ring-error', wrapperClassName), children: [jsxRuntime.jsx(uiIcons.SearchLg, { "aria-hidden": "true", className: cx.cx('pointer-events-none absolute text-fg-quaternary', sizes[size].icon) }), jsxRuntime.jsx(reactAriaComponents.Input, { ref: ref, "data-testid": inputTestId, placeholder: placeholder, className: cx.cx(
26
+ // The browser draws its own cancel control on a search input; the clear button below replaces it.
27
+ 'm-0 w-full bg-transparent text-primary ring-0 outline-hidden placeholder:text-placeholder disabled:cursor-not-allowed [&::-webkit-search-cancel-button]:hidden', sizes[size].input, inputClassName) }), jsxRuntime.jsx(reactAriaComponents.Button, { "aria-label": clearLabel, "data-testid": testIdUtils.joinTestId(inputTestId, 'clear'), className: cx.cx('absolute flex cursor-pointer items-center justify-center rounded-md p-1 text-fg-quaternary outline-focus-ring transition duration-100 ease-linear group-data-empty/search:hidden group-data-disabled/search:hidden group-data-readonly/search:hidden hover:text-fg-quaternary_hover focus-visible:outline-2', sizes[size].clear), children: jsxRuntime.jsx(uiIcons.XClose, { "aria-hidden": "true", className: "size-4 stroke-[2.25px]" }) }), shortcut && (jsxRuntime.jsx("div", { className: cx.cx('pointer-events-none absolute inset-y-0.5 right-0.5 z-10 hidden items-center rounded-r-[inherit] bg-linear-to-r from-transparent to-bg-primary to-40% pl-8 group-data-empty/search:md:flex', sizes[size].shortcut), children: jsxRuntime.jsx("span", { "aria-hidden": "true", className: "rounded px-1 py-px text-xs font-medium text-quaternary ring-1 ring-secondary select-none ring-inset", children: shortcutLabel }) }))] }), hint && jsxRuntime.jsx(Input.HintText, { isInvalid: isInvalid, children: hint })] })) }));
28
+ };
29
+ SearchInput.displayName = 'SearchInput';
30
+
31
+ exports.SearchInput = SearchInput;
32
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/atoms/SearchInput/index.tsx"],"sourcesContent":[null],"names":["sortCx","useResolvedTestId","useHotkeyHint","_jsx","AriaSearchField","cx","_jsxs","_Fragment","Label","AriaGroup","SearchLg","AriaInput","AriaButton","joinTestId","XClose","HintText"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { ReactNode, Ref } from 'react';
2
+ import type { SearchFieldProps as AriaSearchFieldProps } from 'react-aria-components';
3
+ export interface SearchInputProps extends Omit<AriaSearchFieldProps, 'children' | 'className' | 'style'> {
4
+ /** Visible label above the field. Without one, pass `aria-label`; the placeholder alone does not name the field once it holds a value. */
5
+ label?: string;
6
+ /** Helper text under the field. */
7
+ hint?: ReactNode;
8
+ /** Placeholder shown while the field is empty. */
9
+ placeholder?: string;
10
+ /** Height, padding and text size. */
11
+ size?: 'sm' | 'md' | 'lg';
12
+ /** Accessible name of the clear button. */
13
+ clearLabel?: string;
14
+ /**
15
+ * Keyboard shortcut hint shown while the field is empty. `true` shows the search shortcut (⌘K on
16
+ * macOS, Ctrl K elsewhere); a shortcut such as `mod+j` is drawn for the user's platform.
17
+ */
18
+ shortcut?: string | boolean;
19
+ /** Extra classes merged onto the outer field. */
20
+ className?: string;
21
+ /** Extra classes merged onto the bordered group around the input. */
22
+ wrapperClassName?: string;
23
+ /** Extra classes merged onto the `<input>`. */
24
+ inputClassName?: string;
25
+ /** Ref forwarded to the `<input>`. */
26
+ ref?: Ref<HTMLInputElement>;
27
+ /** Overrides the `<input>`'s `data-testid` (defaults to `fd-search-input`). The clear button derives `<root>--clear`. */
28
+ 'data-testid'?: string;
29
+ }
30
+ /**
31
+ * A search box with a magnifier, a clear button once it holds text, and Escape to clear. Use it
32
+ * wherever typing filters a list or table; for a field that collects a value, use `Input`.
33
+ *
34
+ * @summary search box that filters as you type and clears in one press
35
+ */
36
+ export declare const SearchInput: {
37
+ ({ label, hint, placeholder, size, clearLabel, shortcut, className, wrapperClassName, inputClassName, ref, "data-testid": dataTestId, ...props }: SearchInputProps): import("react").JSX.Element;
38
+ displayName: string;
39
+ };
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/atoms/SearchInput/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAUtF,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;IACtG,0IAA0I;IAC1I,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC5B,yHAAyH;IACzH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW;sJAarB,gBAAgB;;CAuElB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { SearchLg, XClose } from '@flipdish/ui-icons';
3
+ import { Label, HintText } from '@flipdish/ui-library/components/atoms/Input';
4
+ import { sortCx, cx } from '@flipdish/ui-library/utilities/cx';
5
+ import { useResolvedTestId, joinTestId } from '@flipdish/ui-library/utilities/testIdUtils';
6
+ import { SearchField, Group, Input, Button } from 'react-aria-components';
7
+ import { useHotkeyHint } from '../../../hooks/__internal__/useHotkeyHint/useHotkeyHint.js';
8
+
9
+ const sizes = sortCx({
10
+ sm: { input: 'py-2 pr-9 pl-9 text-sm', icon: 'left-3 size-4 stroke-[2.25px]', clear: 'right-2', shortcut: 'pr-1.5' },
11
+ md: { input: 'py-2 pr-9 pl-10 text-md', icon: 'left-3 size-5', clear: 'right-2', shortcut: 'pr-2' },
12
+ lg: { input: 'py-2.5 pr-9.5 pl-10.5 text-md', icon: 'left-3.5 size-5', clear: 'right-2.5', shortcut: 'pr-2.5' },
13
+ });
14
+ /**
15
+ * A search box with a magnifier, a clear button once it holds text, and Escape to clear. Use it
16
+ * wherever typing filters a list or table; for a field that collects a value, use `Input`.
17
+ *
18
+ * @summary search box that filters as you type and clears in one press
19
+ */
20
+ const SearchInput = ({ label, hint, placeholder, size = 'md', clearLabel = 'Clear search', shortcut, className, wrapperClassName, inputClassName, ref, 'data-testid': dataTestId, ...props }) => {
21
+ const inputTestId = useResolvedTestId({ testId: dataTestId, segment: 'search-input', rootName: 'search-input' });
22
+ const shortcutLabel = useHotkeyHint(shortcut === true ? 'mod+k' : shortcut || null);
23
+ return (jsx(SearchField, { "aria-label": label ? undefined : placeholder, ...props, className: cx('group/search flex h-max w-full flex-col items-start gap-1.5', className), children: ({ isInvalid, isDisabled }) => (jsxs(Fragment, { children: [label && jsx(Label, { isInvalid: isInvalid, children: label }), jsxs(Group, { isDisabled: isDisabled, isInvalid: isInvalid, className: ({ isFocusWithin }) => cx('relative flex w-full items-center rounded-lg bg-primary shadow-xs ring-1 ring-primary transition-shadow duration-100 ease-linear ring-inset', isFocusWithin && !isDisabled && 'ring-2 ring-brand', isDisabled && 'cursor-not-allowed opacity-50', isInvalid && 'ring-error_subtle', isInvalid && isFocusWithin && 'ring-2 ring-error', wrapperClassName), children: [jsx(SearchLg, { "aria-hidden": "true", className: cx('pointer-events-none absolute text-fg-quaternary', sizes[size].icon) }), jsx(Input, { ref: ref, "data-testid": inputTestId, placeholder: placeholder, className: cx(
24
+ // The browser draws its own cancel control on a search input; the clear button below replaces it.
25
+ 'm-0 w-full bg-transparent text-primary ring-0 outline-hidden placeholder:text-placeholder disabled:cursor-not-allowed [&::-webkit-search-cancel-button]:hidden', sizes[size].input, inputClassName) }), jsx(Button, { "aria-label": clearLabel, "data-testid": joinTestId(inputTestId, 'clear'), className: cx('absolute flex cursor-pointer items-center justify-center rounded-md p-1 text-fg-quaternary outline-focus-ring transition duration-100 ease-linear group-data-empty/search:hidden group-data-disabled/search:hidden group-data-readonly/search:hidden hover:text-fg-quaternary_hover focus-visible:outline-2', sizes[size].clear), children: jsx(XClose, { "aria-hidden": "true", className: "size-4 stroke-[2.25px]" }) }), shortcut && (jsx("div", { className: cx('pointer-events-none absolute inset-y-0.5 right-0.5 z-10 hidden items-center rounded-r-[inherit] bg-linear-to-r from-transparent to-bg-primary to-40% pl-8 group-data-empty/search:md:flex', sizes[size].shortcut), children: jsx("span", { "aria-hidden": "true", className: "rounded px-1 py-px text-xs font-medium text-quaternary ring-1 ring-secondary select-none ring-inset", children: shortcutLabel }) }))] }), hint && jsx(HintText, { isInvalid: isInvalid, children: hint })] })) }));
26
+ };
27
+ SearchInput.displayName = 'SearchInput';
28
+
29
+ export { SearchInput };
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/atoms/SearchInput/index.tsx"],"sourcesContent":[null],"names":["_jsx","AriaSearchField","_jsxs","_Fragment","AriaGroup","AriaInput","AriaButton"],"mappings":"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"}
@@ -1,5 +1,74 @@
1
1
  'use strict';
2
2
 
3
+ var core = require('shiki/core');
4
+ var javascript = require('shiki/engine/javascript');
5
+ var langs = require('shiki/langs');
6
+
7
+ /** The two themes a snippet renders, with GitHub's token colours replaced by the design tokens. */
8
+ const HIGHLIGHT_THEMES = {
9
+ defaultColor: 'light',
10
+ themes: { light: 'github-light', dark: 'github-dark' },
11
+ colorReplacements: {
12
+ 'github-light': {
13
+ '#24292e': 'var(--color-text-primary)',
14
+ '#005cc5': 'var(--color-utility-blue-600)',
15
+ '#d73a49': 'var(--color-utility-pink-600)',
16
+ '#6f42c1': 'var(--color-utility-brand-600)',
17
+ '#032f62': 'var(--color-primary)',
18
+ },
19
+ 'github-dark': {
20
+ '#e1e4e8': 'var(--color-text-primary)',
21
+ '#79b8ff': 'var(--color-utility-blue-600)',
22
+ '#f97583': 'var(--color-utility-pink-600)',
23
+ '#b392f0': 'var(--color-utility-brand-600)',
24
+ '#9ecbff': 'var(--color-primary)',
25
+ },
26
+ },
27
+ };
28
+ // One highlighter for every snippet, built on first use with no grammars: each language loads as its own chunk the first
29
+ // time a snippet asks for it. The JavaScript regex engine means no WASM download before the first highlight.
30
+ let highlighterPromise = null;
31
+ /**
32
+ * The shared highlighter, created on the first call and reused by every snippet after that.
33
+ * @returns The core highlighter with both themes loaded and no grammars yet.
34
+ */
35
+ const getHighlighter = () => {
36
+ highlighterPromise ?? (highlighterPromise = core.createHighlighterCore({
37
+ // Forgiving skips the few grammar patterns the engine cannot express instead of throwing, which costs a token's colour
38
+ // at most. The engine needs the RegExp `d` flag, so Chrome 90 and Safari 15 are the floor.
39
+ engine: javascript.createJavaScriptRegexEngine({ forgiving: true }),
40
+ langs: [],
41
+ themes: [import('shiki/themes/github-light.mjs'), import('shiki/themes/github-dark.mjs')],
42
+ }).catch((error) => {
43
+ // A failed creation, such as a theme chunk that did not load, must not pin every later snippet to the same rejection.
44
+ highlighterPromise = null;
45
+ throw error;
46
+ }));
47
+ return highlighterPromise;
48
+ };
49
+ // Own keys only: `in` would also accept `toString` and the other prototype names.
50
+ const languageIds = new Set(Object.keys(langs.bundledLanguages));
51
+ /**
52
+ * Whether Shiki has a grammar for the language, as opposed to a special language such as `text` or a typo.
53
+ * @param language The `language` prop as given.
54
+ * @returns `true` when a grammar can be loaded for it.
55
+ */
56
+ const isBundledLanguage = (language) => languageIds.has(language);
57
+ /**
58
+ * Highlights source into a hast tree with the snippet's themes, loading the language's grammar on first use. A language
59
+ * with no grammar, including a typo, highlights as plain text rather than failing, so the snippet still shows the code.
60
+ * @param code The source to highlight.
61
+ * @param language The language id; anything Shiki does not know falls back to `text`.
62
+ * @returns The hast root for `toJsxRuntime`.
63
+ */
64
+ const highlightToHast = async (code, language) => {
65
+ const highlighter = await getHighlighter();
66
+ // Shiki skips a grammar it already holds, and the module system caches the import, so a repeat is cheap.
67
+ if (isBundledLanguage(language))
68
+ await highlighter.loadLanguage(langs.bundledLanguages[language]);
69
+ const lang = isBundledLanguage(language) || language === 'ansi' ? language : 'text';
70
+ return highlighter.codeToHast(code, { lang, ...HIGHLIGHT_THEMES });
71
+ };
3
72
  /**
4
73
  * Reads the visible tab panel's text so the header copy button copies the active snippet.
5
74
  *
@@ -13,5 +82,9 @@ const getActiveTabPanelText = (root) => {
13
82
  return activePanel?.textContent?.trim() ?? '';
14
83
  };
15
84
 
85
+ exports.HIGHLIGHT_THEMES = HIGHLIGHT_THEMES;
16
86
  exports.getActiveTabPanelText = getActiveTabPanelText;
87
+ exports.getHighlighter = getHighlighter;
88
+ exports.highlightToHast = highlightToHast;
89
+ exports.isBundledLanguage = isBundledLanguage;
17
90
  //# sourceMappingURL=codeSnippet.utils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"codeSnippet.utils.cjs","sources":["../../../../src/components/molecules/CodeSnippet/codeSnippet.utils.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;AAKG;AACI,MAAM,qBAAqB,GAAG,CAAC,IAAuB,KAAY;AACvE,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,EAAE;IACpB,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,iCAAiC,CAAC;IACzE,OAAO,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;AAC/C;;"}
1
+ {"version":3,"file":"codeSnippet.utils.cjs","sources":["../../../../src/components/molecules/CodeSnippet/codeSnippet.utils.ts"],"sourcesContent":[null],"names":["createHighlighterCore","createJavaScriptRegexEngine","bundledLanguages"],"mappings":";;;;;;AAQA;AACO,MAAM,gBAAgB,GAAG;AAC9B,IAAA,YAAY,EAAE,OAAO;IACrB,MAAM,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE;AACtD,IAAA,iBAAiB,EAAE;AACjB,QAAA,cAAc,EAAE;AACd,YAAA,SAAS,EAAE,2BAA2B;AACtC,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,gCAAgC;AAC3C,YAAA,SAAS,EAAE,sBAAsB;AAClC,SAAA;AACD,QAAA,aAAa,EAAE;AACb,YAAA,SAAS,EAAE,2BAA2B;AACtC,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,gCAAgC;AAC3C,YAAA,SAAS,EAAE,sBAAsB;AAClC,SAAA;AACF,KAAA;;AAGH;AACA;AACA,IAAI,kBAAkB,GAAoC,IAAI;AAE9D;;;AAGG;AACI,MAAM,cAAc,GAAG,MAA+B;AAC3D,IAAA,kBAAkB,KAAlB,kBAAkB,GAAKA,0BAAqB,CAAC;;;QAG3C,MAAM,EAAEC,sCAA2B,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACxD,QAAA,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,+BAA+B,CAAC,EAAE,OAAO,8BAA8B,CAAC,CAAC;AAC1F,KAAA,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,KAAI;;QAE1B,kBAAkB,GAAG,IAAI;AACzB,QAAA,MAAM,KAAK;AACb,IAAA,CAAC,CAAC,CAAA;AACF,IAAA,OAAO,kBAAkB;AAC3B;AAEA;AACA,MAAM,WAAW,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,IAAI,CAACC,sBAAgB,CAAC,CAAC;AAElE;;;;AAIG;AACI,MAAM,iBAAiB,GAAG,CAAC,QAAgB,KAAkC,WAAW,CAAC,GAAG,CAAC,QAAQ;AAE5G;;;;;;AAMG;AACI,MAAM,eAAe,GAAG,OAAO,IAAY,EAAE,QAAmB,KAAwD;AAC7H,IAAA,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE;;IAE1C,IAAI,iBAAiB,CAAC,QAAQ,CAAC;QAAE,MAAM,WAAW,CAAC,YAAY,CAACA,sBAAgB,CAAC,QAAQ,CAAC,CAAC;AAC3F,IAAA,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,MAAM,GAAG,QAAQ,GAAG,MAAM;AACnF,IAAA,OAAO,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAC;AACpE;AAEA;;;;;AAKG;AACI,MAAM,qBAAqB,GAAG,CAAC,IAAuB,KAAY;AACvE,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,EAAE;IACpB,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,iCAAiC,CAAC;IACzE,OAAO,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;AAC/C;;;;;;"}
@@ -1,3 +1,51 @@
1
+ import { type HighlighterCore } from 'shiki/core';
2
+ import { type BundledLanguage } from 'shiki/langs';
3
+ import type { SpecialLanguage } from 'shiki/types';
4
+ /** Any of Shiki's languages, or a special one such as `text` that needs no grammar. */
5
+ export type Languages = BundledLanguage | SpecialLanguage;
6
+ /** The two themes a snippet renders, with GitHub's token colours replaced by the design tokens. */
7
+ export declare const HIGHLIGHT_THEMES: {
8
+ readonly defaultColor: "light";
9
+ readonly themes: {
10
+ readonly light: "github-light";
11
+ readonly dark: "github-dark";
12
+ };
13
+ readonly colorReplacements: {
14
+ readonly 'github-light': {
15
+ readonly '#24292e': "var(--color-text-primary)";
16
+ readonly '#005cc5': "var(--color-utility-blue-600)";
17
+ readonly '#d73a49': "var(--color-utility-pink-600)";
18
+ readonly '#6f42c1': "var(--color-utility-brand-600)";
19
+ readonly '#032f62': "var(--color-primary)";
20
+ };
21
+ readonly 'github-dark': {
22
+ readonly '#e1e4e8': "var(--color-text-primary)";
23
+ readonly '#79b8ff': "var(--color-utility-blue-600)";
24
+ readonly '#f97583': "var(--color-utility-pink-600)";
25
+ readonly '#b392f0': "var(--color-utility-brand-600)";
26
+ readonly '#9ecbff': "var(--color-primary)";
27
+ };
28
+ };
29
+ };
30
+ /**
31
+ * The shared highlighter, created on the first call and reused by every snippet after that.
32
+ * @returns The core highlighter with both themes loaded and no grammars yet.
33
+ */
34
+ export declare const getHighlighter: () => Promise<HighlighterCore>;
35
+ /**
36
+ * Whether Shiki has a grammar for the language, as opposed to a special language such as `text` or a typo.
37
+ * @param language The `language` prop as given.
38
+ * @returns `true` when a grammar can be loaded for it.
39
+ */
40
+ export declare const isBundledLanguage: (language: string) => language is BundledLanguage;
41
+ /**
42
+ * Highlights source into a hast tree with the snippet's themes, loading the language's grammar on first use. A language
43
+ * with no grammar, including a typo, highlights as plain text rather than failing, so the snippet still shows the code.
44
+ * @param code The source to highlight.
45
+ * @param language The language id; anything Shiki does not know falls back to `text`.
46
+ * @returns The hast root for `toJsxRuntime`.
47
+ */
48
+ export declare const highlightToHast: (code: string, language: Languages) => Promise<ReturnType<HighlighterCore["codeToHast"]>>;
1
49
  /**
2
50
  * Reads the visible tab panel's text so the header copy button copies the active snippet.
3
51
  *
@@ -1 +1 @@
1
- {"version":3,"file":"codeSnippet.utils.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/CodeSnippet/codeSnippet.utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM,UAAU,GAAG,IAAI,KAAG,MAI/D,CAAC"}
1
+ {"version":3,"file":"codeSnippet.utils.d.ts","sourceRoot":"","sources":["../../../../src/components/molecules/CodeSnippet/codeSnippet.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzE,OAAO,EAAE,KAAK,eAAe,EAAoB,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,uFAAuF;AACvF,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,eAAe,CAAC;AAE1D,mGAAmG;AACnG,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;CAmBnB,CAAC;AAMX;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,OAAO,CAAC,eAAe,CAaxD,CAAC;AAKF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,MAAM,KAAG,QAAQ,IAAI,eAA4C,CAAC;AAE9G;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAU,MAAM,MAAM,EAAE,UAAU,SAAS,KAAG,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAM1H,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM,UAAU,GAAG,IAAI,KAAG,MAI/D,CAAC"}
@@ -1,3 +1,72 @@
1
+ import { createHighlighterCore } from 'shiki/core';
2
+ import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';
3
+ import { bundledLanguages } from 'shiki/langs';
4
+
5
+ /** The two themes a snippet renders, with GitHub's token colours replaced by the design tokens. */
6
+ const HIGHLIGHT_THEMES = {
7
+ defaultColor: 'light',
8
+ themes: { light: 'github-light', dark: 'github-dark' },
9
+ colorReplacements: {
10
+ 'github-light': {
11
+ '#24292e': 'var(--color-text-primary)',
12
+ '#005cc5': 'var(--color-utility-blue-600)',
13
+ '#d73a49': 'var(--color-utility-pink-600)',
14
+ '#6f42c1': 'var(--color-utility-brand-600)',
15
+ '#032f62': 'var(--color-primary)',
16
+ },
17
+ 'github-dark': {
18
+ '#e1e4e8': 'var(--color-text-primary)',
19
+ '#79b8ff': 'var(--color-utility-blue-600)',
20
+ '#f97583': 'var(--color-utility-pink-600)',
21
+ '#b392f0': 'var(--color-utility-brand-600)',
22
+ '#9ecbff': 'var(--color-primary)',
23
+ },
24
+ },
25
+ };
26
+ // One highlighter for every snippet, built on first use with no grammars: each language loads as its own chunk the first
27
+ // time a snippet asks for it. The JavaScript regex engine means no WASM download before the first highlight.
28
+ let highlighterPromise = null;
29
+ /**
30
+ * The shared highlighter, created on the first call and reused by every snippet after that.
31
+ * @returns The core highlighter with both themes loaded and no grammars yet.
32
+ */
33
+ const getHighlighter = () => {
34
+ highlighterPromise ?? (highlighterPromise = createHighlighterCore({
35
+ // Forgiving skips the few grammar patterns the engine cannot express instead of throwing, which costs a token's colour
36
+ // at most. The engine needs the RegExp `d` flag, so Chrome 90 and Safari 15 are the floor.
37
+ engine: createJavaScriptRegexEngine({ forgiving: true }),
38
+ langs: [],
39
+ themes: [import('shiki/themes/github-light.mjs'), import('shiki/themes/github-dark.mjs')],
40
+ }).catch((error) => {
41
+ // A failed creation, such as a theme chunk that did not load, must not pin every later snippet to the same rejection.
42
+ highlighterPromise = null;
43
+ throw error;
44
+ }));
45
+ return highlighterPromise;
46
+ };
47
+ // Own keys only: `in` would also accept `toString` and the other prototype names.
48
+ const languageIds = new Set(Object.keys(bundledLanguages));
49
+ /**
50
+ * Whether Shiki has a grammar for the language, as opposed to a special language such as `text` or a typo.
51
+ * @param language The `language` prop as given.
52
+ * @returns `true` when a grammar can be loaded for it.
53
+ */
54
+ const isBundledLanguage = (language) => languageIds.has(language);
55
+ /**
56
+ * Highlights source into a hast tree with the snippet's themes, loading the language's grammar on first use. A language
57
+ * with no grammar, including a typo, highlights as plain text rather than failing, so the snippet still shows the code.
58
+ * @param code The source to highlight.
59
+ * @param language The language id; anything Shiki does not know falls back to `text`.
60
+ * @returns The hast root for `toJsxRuntime`.
61
+ */
62
+ const highlightToHast = async (code, language) => {
63
+ const highlighter = await getHighlighter();
64
+ // Shiki skips a grammar it already holds, and the module system caches the import, so a repeat is cheap.
65
+ if (isBundledLanguage(language))
66
+ await highlighter.loadLanguage(bundledLanguages[language]);
67
+ const lang = isBundledLanguage(language) || language === 'ansi' ? language : 'text';
68
+ return highlighter.codeToHast(code, { lang, ...HIGHLIGHT_THEMES });
69
+ };
1
70
  /**
2
71
  * Reads the visible tab panel's text so the header copy button copies the active snippet.
3
72
  *
@@ -11,5 +80,5 @@ const getActiveTabPanelText = (root) => {
11
80
  return activePanel?.textContent?.trim() ?? '';
12
81
  };
13
82
 
14
- export { getActiveTabPanelText };
83
+ export { HIGHLIGHT_THEMES, getActiveTabPanelText, getHighlighter, highlightToHast, isBundledLanguage };
15
84
  //# sourceMappingURL=codeSnippet.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"codeSnippet.utils.js","sources":["../../../../src/components/molecules/CodeSnippet/codeSnippet.utils.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;AAKG;AACI,MAAM,qBAAqB,GAAG,CAAC,IAAuB,KAAY;AACvE,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,EAAE;IACpB,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,iCAAiC,CAAC;IACzE,OAAO,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;AAC/C;;"}
1
+ {"version":3,"file":"codeSnippet.utils.js","sources":["../../../../src/components/molecules/CodeSnippet/codeSnippet.utils.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;AAQA;AACO,MAAM,gBAAgB,GAAG;AAC9B,IAAA,YAAY,EAAE,OAAO;IACrB,MAAM,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE;AACtD,IAAA,iBAAiB,EAAE;AACjB,QAAA,cAAc,EAAE;AACd,YAAA,SAAS,EAAE,2BAA2B;AACtC,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,gCAAgC;AAC3C,YAAA,SAAS,EAAE,sBAAsB;AAClC,SAAA;AACD,QAAA,aAAa,EAAE;AACb,YAAA,SAAS,EAAE,2BAA2B;AACtC,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,+BAA+B;AAC1C,YAAA,SAAS,EAAE,gCAAgC;AAC3C,YAAA,SAAS,EAAE,sBAAsB;AAClC,SAAA;AACF,KAAA;;AAGH;AACA;AACA,IAAI,kBAAkB,GAAoC,IAAI;AAE9D;;;AAGG;AACI,MAAM,cAAc,GAAG,MAA+B;AAC3D,IAAA,kBAAkB,KAAlB,kBAAkB,GAAK,qBAAqB,CAAC;;;QAG3C,MAAM,EAAE,2BAA2B,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACxD,QAAA,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,+BAA+B,CAAC,EAAE,OAAO,8BAA8B,CAAC,CAAC;AAC1F,KAAA,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,KAAI;;QAE1B,kBAAkB,GAAG,IAAI;AACzB,QAAA,MAAM,KAAK;AACb,IAAA,CAAC,CAAC,CAAA;AACF,IAAA,OAAO,kBAAkB;AAC3B;AAEA;AACA,MAAM,WAAW,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAElE;;;;AAIG;AACI,MAAM,iBAAiB,GAAG,CAAC,QAAgB,KAAkC,WAAW,CAAC,GAAG,CAAC,QAAQ;AAE5G;;;;;;AAMG;AACI,MAAM,eAAe,GAAG,OAAO,IAAY,EAAE,QAAmB,KAAwD;AAC7H,IAAA,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE;;IAE1C,IAAI,iBAAiB,CAAC,QAAQ,CAAC;QAAE,MAAM,WAAW,CAAC,YAAY,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;AAC3F,IAAA,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,MAAM,GAAG,QAAQ,GAAG,MAAM;AACnF,IAAA,OAAO,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAC;AACpE;AAEA;;;;;AAKG;AACI,MAAM,qBAAqB,GAAG,CAAC,IAAuB,KAAY;AACvE,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,EAAE;IACpB,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,iCAAiC,CAAC;IACzE,OAAO,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;AAC/C;;"}
@@ -1,20 +1,42 @@
1
1
  'use strict';
2
2
 
3
+ var renderUtils = require('@flipdish/ui-library/utilities/renderUtils');
3
4
  var React = require('react');
4
5
 
5
6
  /**
6
7
  * Replaces the fallback nodes with syntax-highlighted nodes once `code` has been highlighted.
7
- * The first paint keeps the fallback so the snippet is not blank while highlighting runs.
8
+ * The first paint keeps the fallback so the snippet is not blank while highlighting runs, and a
9
+ * highlight that fails or is superseded by a newer `code` or `language` never replaces it.
8
10
  *
9
11
  * @param options The snippet source, its language, the nodes shown before highlighting finishes, and the highlighter.
10
12
  * @returns The nodes to render inside the code block.
11
13
  */
12
14
  const useCodeSnippetHighlight = ({ code, language, fallback, highlightCode, }) => {
13
15
  const [nodes, setNodes] = React.useState(fallback);
16
+ // Synced after commit, so a rejection never shows a fallback from a render React threw away.
17
+ const fallbackRef = React.useRef(fallback);
18
+ React.useLayoutEffect(() => {
19
+ fallbackRef.current = fallback;
20
+ }, [fallback]);
14
21
  React.useLayoutEffect(() => {
15
22
  if (!code)
16
23
  return;
17
- void highlightCode(code, language).then(setNodes);
24
+ // Grammars load on first use, so an earlier highlight can finish after a later one; only the latest request may render.
25
+ let stale = false;
26
+ highlightCode(code, language).then((highlighted) => {
27
+ if (!stale)
28
+ setNodes(highlighted);
29
+ }, (error) => {
30
+ // A failed highlight, such as a theme chunk that did not load, shows the plain code rather than an older highlight.
31
+ if (stale)
32
+ return;
33
+ setNodes(fallbackRef.current);
34
+ if (!renderUtils.isProductionBuild())
35
+ console.warn('CodeSnippet: highlighting failed, showing plain code.', error);
36
+ });
37
+ return () => {
38
+ stale = true;
39
+ };
18
40
  }, [code, language, highlightCode]);
19
41
  return nodes;
20
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useCodeSnippetHighlight.cjs","sources":["../../../../../src/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.ts"],"sourcesContent":[null],"names":["useState","useLayoutEffect"],"mappings":";;;;AAeA;;;;;;AAMG;AACI,MAAM,uBAAuB,GAAG,CAA0B,EAC/D,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,aAAa,GAC4B,KAAe;IACxD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAGA,cAAQ,CAAC,QAAQ,CAAC;IAE5CC,qBAAe,CAAC,MAAK;AACnB,QAAA,IAAI,CAAC,IAAI;YAAE;QACX,KAAK,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACnD,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEnC,IAAA,OAAO,KAAK;AACd;;"}
1
+ {"version":3,"file":"useCodeSnippetHighlight.cjs","sources":["../../../../../src/components/molecules/CodeSnippet/hooks/useCodeSnippetHighlight.ts"],"sourcesContent":[null],"names":["useState","useRef","useLayoutEffect","isProductionBuild"],"mappings":";;;;;AAgBA;;;;;;;AAOG;AACI,MAAM,uBAAuB,GAAG,CAA0B,EAC/D,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,aAAa,GAC4B,KAAe;IACxD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAGA,cAAQ,CAAC,QAAQ,CAAC;;AAE5C,IAAA,MAAM,WAAW,GAAGC,YAAM,CAAC,QAAQ,CAAC;IACpCC,qBAAe,CAAC,MAAK;AACnB,QAAA,WAAW,CAAC,OAAO,GAAG,QAAQ;AAChC,IAAA,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAEdA,qBAAe,CAAC,MAAK;AACnB,QAAA,IAAI,CAAC,IAAI;YAAE;;QAEX,IAAI,KAAK,GAAG,KAAK;QACjB,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAChC,CAAC,WAAW,KAAI;AACd,YAAA,IAAI,CAAC,KAAK;gBAAE,QAAQ,CAAC,WAAW,CAAC;AACnC,QAAA,CAAC,EACD,CAAC,KAAc,KAAI;;AAEjB,YAAA,IAAI,KAAK;gBAAE;AACX,YAAA,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC;YAC7B,IAAI,CAACC,6BAAiB,EAAE;AAAE,gBAAA,OAAO,CAAC,IAAI,CAAC,uDAAuD,EAAE,KAAK,CAAC;AACxG,QAAA,CAAC,CACF;AACD,QAAA,OAAO,MAAK;YACV,KAAK,GAAG,IAAI;AACd,QAAA,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEnC,IAAA,OAAO,KAAK;AACd;;"}