@flipdish/ui-library 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -77,6 +77,61 @@ Import the library's shared runtime from your CSS entry **in this exact layer or
77
77
  @import "tailwindcss/utilities.css" layer(utilities);
78
78
  ```
79
79
 
80
+ ## Scoping Tailwind CSS to a subtree
81
+
82
+ When your app doesn't own the whole page — a widget, an embed, a Storybook preview, a multi-tenant host, or a micro-frontend — its Tailwind v4 output (utilities **and** Preflight resets) can leak into or clash with the surrounding CSS. The fix is to scope every emitted selector under a single mount element.
83
+
84
+ `@flipdish/ui-library/utilities/cssScopeUtils` ships `createScopedPrefixTransform`, a small factory for [`postcss-prefix-selector`](https://www.npmjs.com/package/postcss-prefix-selector) that consolidates the scoping rules (scope `:root`/`html` so `@theme` tokens and base typography cascade only within the subtree, leave `:host` and `@keyframes` steps alone, never double-prefix, etc.) so you write one line instead of copy-pasting a bespoke transform.
85
+
86
+ Install the companion plugin (an optional peer):
87
+
88
+ ```bash
89
+ pnpm add -D postcss-prefix-selector
90
+ ```
91
+
92
+ Then add it to your PostCSS config:
93
+
94
+ ```js
95
+ // postcss.config.mjs
96
+ import prefixSelector from "postcss-prefix-selector";
97
+ import { createScopedPrefixTransform } from "@flipdish/ui-library/utilities/cssScopeUtils";
98
+
99
+ const SCOPE = "#flipdish-micro-frontend"; // the id/attribute on your mount node
100
+
101
+ export default {
102
+ plugins: [
103
+ prefixSelector({
104
+ prefix: SCOPE,
105
+ transform: createScopedPrefixTransform(SCOPE),
106
+ }),
107
+ ],
108
+ };
109
+ ```
110
+
111
+ Tailwind's output becomes plain `#flipdish-micro-frontend .px-4 { … }`, which every downstream tool (Vite, lightningcss) understands.
112
+
113
+ ### Options
114
+
115
+ `createScopedPrefixTransform(scopeSelector, options?)`:
116
+
117
+ | Option | Type | Default | Description |
118
+ | ------------------ | -------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
119
+ | `shouldScope` | `(filePath: string \| undefined) => boolean` | `() => true` | Return `false` to leave a file's selectors untouched (e.g. third-party CSS you don't want prefixed). |
120
+ | `scopeBody` | `boolean` | `false` | Scope Preflight `body` resets to the mount selector instead of leaving `body` global. Enable when the host page must not inherit the reset. |
121
+ | `matchRootElement` | `boolean` | `false` | Also emit a compound selector so the scope root element itself matches class selectors (e.g. `<div data-scope class="flex-1">`). |
122
+
123
+ ```js
124
+ createScopedPrefixTransform("[data-tailwind]", {
125
+ shouldScope: (file) => !file || !file.includes("node_modules"),
126
+ scopeBody: true,
127
+ matchRootElement: true,
128
+ });
129
+ ```
130
+
131
+ > **Why PostCSS and not Tailwind's `important(#selector)`?** Tailwind v4's `important(...)` syntax emits non-standard `@media important(...)` blocks that lightningcss can't parse during minification, so scoping is done as a PostCSS pass over Tailwind's output instead.
132
+
133
+ Micro-frontends are one use case; the same transform applies to widgets, embeds, Storybook, and multi-tenant UIs.
134
+
80
135
  ## Documentation
81
136
 
82
137
  Full component docs, interactive examples, and design guidance live in the [Storybook](https://flipdishbytes.github.io/flipdish-design-system/).
@@ -28,13 +28,17 @@ const baseStyles = {
28
28
  },
29
29
  };
30
30
  const BreadcrumbBase = ({ href, children, icon: Icon, type = 'text', current, className, ...otherProps }) => {
31
- return (jsxRuntime.jsxs(reactAriaComponents.Link, { ...otherProps, href: href, className: (state) => cx.cx('group inline-flex items-center justify-center gap-1 rounded-md outline-focus-ring transition duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2 in-current:max-w-full', baseStyles[type].root, current && baseStyles[type].current.root, (href || otherProps.onClick) && 'cursor-pointer', typeof className === 'function' ? className(state) : className), children: [isReactComponent.isReactComponent(Icon) && (jsxRuntime.jsx(Icon, { className: cx.cx('size-5 transition-inherit-all', baseStyles[type].icon, current && baseStyles[type].current.icon) })), React.isValidElement(Icon) && Icon, children && (jsxRuntime.jsx("span", { className: cx.cx('text-sm font-semibold whitespace-nowrap transition-inherit-all in-current:truncate', baseStyles[type].label, current && baseStyles[type].current.label), children: children }))] }));
31
+ return (jsxRuntime.jsxs(reactAriaComponents.Link, { ...otherProps,
32
+ // Guard against an empty-string href: react-aria renders `<a>` only for a truthy
33
+ // href (a falsy value renders a non-navigable `<span role="link">`), so coerce
34
+ // `''`/undefined to undefined to keep href-less/current items non-interactive.
35
+ href: href || undefined, className: (state) => cx.cx('group inline-flex items-center justify-center gap-1 rounded-md outline-focus-ring transition duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2 in-current:max-w-full', baseStyles[type].root, current && baseStyles[type].current.root, (href || otherProps.onClick) && 'cursor-pointer', typeof className === 'function' ? className(state) : className), children: [isReactComponent.isReactComponent(Icon) && (jsxRuntime.jsx(Icon, { className: cx.cx('size-5 transition-inherit-all', baseStyles[type].icon, current && baseStyles[type].current.icon) })), React.isValidElement(Icon) && Icon, children && (jsxRuntime.jsx("span", { className: cx.cx('text-sm font-semibold whitespace-nowrap transition-inherit-all in-current:truncate', baseStyles[type].label, current && baseStyles[type].current.label), children: children }))] }));
32
36
  };
33
37
  const BreadcrumbItem = ({ href, icon, divider, type, isEllipsis, children, onClick, avatarSrc, className, ...otherProps }) => {
34
38
  const context = React.useContext(index.BreadcrumbsContext);
35
39
  type = context.type || 'text';
36
40
  divider = context.divider || 'chevron';
37
- return (jsxRuntime.jsx(reactAriaComponents.Breadcrumb, { ...otherProps, className: cx.cx('flex items-center current:overflow-hidden', avatarSrc ? 'gap-1.5 md:gap-2' : type === 'text' || type === 'text-line' ? 'gap-1.5 md:gap-2' : 'gap-0.5 md:gap-1', className), children: ({ isCurrent }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [avatarSrc ? (jsxRuntime.jsxs(reactAriaComponents.Link, { href: href, className: ({ isPressed, isFocusVisible }) => cx.cx('flex cursor-pointer items-center gap-1.5 rounded-lg outline-0 outline-offset-2 outline-focus-ring', (isPressed || isFocusVisible) && 'outline-2'), children: [jsxRuntime.jsx("div", { className: "flex rounded-lg bg-primary p-0.5 ring-[0.5px] ring-secondary ring-inset", children: jsxRuntime.jsx(Avatar.Avatar, { size: "xs", src: avatarSrc, className: "shadow-md", contentClassName: "rounded-md before:hidden" }) }), children && jsxRuntime.jsx("span", { className: "text-sm font-semibold text-primary", children: children })] })) : isEllipsis ? (jsxRuntime.jsx(BreadcrumbBase
41
+ return (jsxRuntime.jsx(reactAriaComponents.Breadcrumb, { ...otherProps, className: cx.cx('flex items-center current:overflow-hidden', avatarSrc ? 'gap-1.5 md:gap-2' : type === 'text' || type === 'text-line' ? 'gap-1.5 md:gap-2' : 'gap-0.5 md:gap-1', className), children: ({ isCurrent }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [avatarSrc ? (jsxRuntime.jsxs(reactAriaComponents.Link, { href: href || undefined, className: ({ isPressed, isFocusVisible }) => cx.cx('flex cursor-pointer items-center gap-1.5 rounded-lg outline-0 outline-offset-2 outline-focus-ring', (isPressed || isFocusVisible) && 'outline-2'), children: [jsxRuntime.jsx("div", { className: "flex rounded-lg bg-primary p-0.5 ring-[0.5px] ring-secondary ring-inset", children: jsxRuntime.jsx(Avatar.Avatar, { size: "xs", src: avatarSrc, className: "shadow-md", contentClassName: "rounded-md before:hidden" }) }), children && jsxRuntime.jsx("span", { className: "text-sm font-semibold text-primary", children: children })] })) : isEllipsis ? (jsxRuntime.jsx(BreadcrumbBase
38
42
  // The label for screen readers.
39
43
  , { "aria-label": "See all breadcrumb items", type: type === 'text-line' ? 'text' : type, onClick: onClick, children: "..." })) : (jsxRuntime.jsx(BreadcrumbBase, { href: href, icon: icon, current: isCurrent, type: type === 'text-line' ? 'text' : type, onClick: onClick, children: children })), !isCurrent &&
40
44
  (divider === 'slash' ? (jsxRuntime.jsx(uiIcons.SlashDivider, { className: "size-4 shrink-0 stroke-[2.25px] text-utility-neutral-300" })) : (jsxRuntime.jsx(uiIcons.ChevronRight, { className: "size-4 shrink-0 stroke-[2.25px] text-utility-neutral-300" })))] })) }));
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb-item.cjs","sources":["../../../../../src/components/molecules/Breadcrumbs/components/breadcrumb-item.tsx"],"sourcesContent":[null],"names":["_jsxs","AriaLink","cx","isReactComponent","_jsx","isValidElement","useContext","BreadcrumbsContext","AriaBreadcrumb","_Fragment","Avatar","SlashDivider","ChevronRight"],"mappings":"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"}
1
+ {"version":3,"file":"breadcrumb-item.cjs","sources":["../../../../../src/components/molecules/Breadcrumbs/components/breadcrumb-item.tsx"],"sourcesContent":[null],"names":["_jsxs","AriaLink","cx","isReactComponent","_jsx","isValidElement","useContext","BreadcrumbsContext","AriaBreadcrumb","_Fragment","Avatar","SlashDivider","ChevronRight"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb-item.d.ts","sourceRoot":"","sources":["../../../../../src/components/molecules/Breadcrumbs/components/breadcrumb-item.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,EAAkB,KAAK,SAAS,EAAc,MAAM,OAAO,CAAC;AAC5E,OAAO,EAEL,KAAK,eAAe,IAAI,mBAAmB,EAG5C,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AA+DnE,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,EAAE,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;IAC9C,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,GAAI,mGAW5B,mBAAmB,gCA0DrB,CAAC"}
1
+ {"version":3,"file":"breadcrumb-item.d.ts","sourceRoot":"","sources":["../../../../../src/components/molecules/Breadcrumbs/components/breadcrumb-item.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,EAAkB,KAAK,SAAS,EAAc,MAAM,OAAO,CAAC;AAC5E,OAAO,EAEL,KAAK,eAAe,IAAI,mBAAmB,EAG5C,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAkEnE,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,EAAE,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC;IAC9C,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,GAAI,mGAW5B,mBAAmB,gCA0DrB,CAAC"}
@@ -26,13 +26,17 @@ const baseStyles = {
26
26
  },
27
27
  };
28
28
  const BreadcrumbBase = ({ href, children, icon: Icon, type = 'text', current, className, ...otherProps }) => {
29
- return (jsxs(Link, { ...otherProps, href: href, className: (state) => cx('group inline-flex items-center justify-center gap-1 rounded-md outline-focus-ring transition duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2 in-current:max-w-full', baseStyles[type].root, current && baseStyles[type].current.root, (href || otherProps.onClick) && 'cursor-pointer', typeof className === 'function' ? className(state) : className), children: [isReactComponent(Icon) && (jsx(Icon, { className: cx('size-5 transition-inherit-all', baseStyles[type].icon, current && baseStyles[type].current.icon) })), isValidElement(Icon) && Icon, children && (jsx("span", { className: cx('text-sm font-semibold whitespace-nowrap transition-inherit-all in-current:truncate', baseStyles[type].label, current && baseStyles[type].current.label), children: children }))] }));
29
+ return (jsxs(Link, { ...otherProps,
30
+ // Guard against an empty-string href: react-aria renders `<a>` only for a truthy
31
+ // href (a falsy value renders a non-navigable `<span role="link">`), so coerce
32
+ // `''`/undefined to undefined to keep href-less/current items non-interactive.
33
+ href: href || undefined, className: (state) => cx('group inline-flex items-center justify-center gap-1 rounded-md outline-focus-ring transition duration-100 ease-linear focus-visible:outline-2 focus-visible:outline-offset-2 in-current:max-w-full', baseStyles[type].root, current && baseStyles[type].current.root, (href || otherProps.onClick) && 'cursor-pointer', typeof className === 'function' ? className(state) : className), children: [isReactComponent(Icon) && (jsx(Icon, { className: cx('size-5 transition-inherit-all', baseStyles[type].icon, current && baseStyles[type].current.icon) })), isValidElement(Icon) && Icon, children && (jsx("span", { className: cx('text-sm font-semibold whitespace-nowrap transition-inherit-all in-current:truncate', baseStyles[type].label, current && baseStyles[type].current.label), children: children }))] }));
30
34
  };
31
35
  const BreadcrumbItem = ({ href, icon, divider, type, isEllipsis, children, onClick, avatarSrc, className, ...otherProps }) => {
32
36
  const context = useContext(BreadcrumbsContext);
33
37
  type = context.type || 'text';
34
38
  divider = context.divider || 'chevron';
35
- return (jsx(Breadcrumb, { ...otherProps, className: cx('flex items-center current:overflow-hidden', avatarSrc ? 'gap-1.5 md:gap-2' : type === 'text' || type === 'text-line' ? 'gap-1.5 md:gap-2' : 'gap-0.5 md:gap-1', className), children: ({ isCurrent }) => (jsxs(Fragment, { children: [avatarSrc ? (jsxs(Link, { href: href, className: ({ isPressed, isFocusVisible }) => cx('flex cursor-pointer items-center gap-1.5 rounded-lg outline-0 outline-offset-2 outline-focus-ring', (isPressed || isFocusVisible) && 'outline-2'), children: [jsx("div", { className: "flex rounded-lg bg-primary p-0.5 ring-[0.5px] ring-secondary ring-inset", children: jsx(Avatar, { size: "xs", src: avatarSrc, className: "shadow-md", contentClassName: "rounded-md before:hidden" }) }), children && jsx("span", { className: "text-sm font-semibold text-primary", children: children })] })) : isEllipsis ? (jsx(BreadcrumbBase
39
+ return (jsx(Breadcrumb, { ...otherProps, className: cx('flex items-center current:overflow-hidden', avatarSrc ? 'gap-1.5 md:gap-2' : type === 'text' || type === 'text-line' ? 'gap-1.5 md:gap-2' : 'gap-0.5 md:gap-1', className), children: ({ isCurrent }) => (jsxs(Fragment, { children: [avatarSrc ? (jsxs(Link, { href: href || undefined, className: ({ isPressed, isFocusVisible }) => cx('flex cursor-pointer items-center gap-1.5 rounded-lg outline-0 outline-offset-2 outline-focus-ring', (isPressed || isFocusVisible) && 'outline-2'), children: [jsx("div", { className: "flex rounded-lg bg-primary p-0.5 ring-[0.5px] ring-secondary ring-inset", children: jsx(Avatar, { size: "xs", src: avatarSrc, className: "shadow-md", contentClassName: "rounded-md before:hidden" }) }), children && jsx("span", { className: "text-sm font-semibold text-primary", children: children })] })) : isEllipsis ? (jsx(BreadcrumbBase
36
40
  // The label for screen readers.
37
41
  , { "aria-label": "See all breadcrumb items", type: type === 'text-line' ? 'text' : type, onClick: onClick, children: "..." })) : (jsx(BreadcrumbBase, { href: href, icon: icon, current: isCurrent, type: type === 'text-line' ? 'text' : type, onClick: onClick, children: children })), !isCurrent &&
38
42
  (divider === 'slash' ? (jsx(SlashDivider, { className: "size-4 shrink-0 stroke-[2.25px] text-utility-neutral-300" })) : (jsx(ChevronRight, { className: "size-4 shrink-0 stroke-[2.25px] text-utility-neutral-300" })))] })) }));
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb-item.js","sources":["../../../../../src/components/molecules/Breadcrumbs/components/breadcrumb-item.tsx"],"sourcesContent":[null],"names":["_jsxs","AriaLink","_jsx","AriaBreadcrumb","_Fragment"],"mappings":";;;;;;;;;AAeA,MAAM,UAAU,GAAG;AACjB,IAAA,IAAI,EAAE;AACJ,QAAA,IAAI,EAAE,EAAE;AACR,QAAA,IAAI,EAAE,yDAAyD;AAC/D,QAAA,KAAK,EAAE,iDAAiD;AACxD,QAAA,OAAO,EAAE;AACP,YAAA,IAAI,EAAE,EAAE;AACR,YAAA,IAAI,EAAE,yDAAyD;AAC/D,YAAA,KAAK,EAAE,uDAAuD;AAC/D,SAAA;AACF,KAAA;AACD,IAAA,MAAM,EAAE;AACN,QAAA,IAAI,EAAE,4BAA4B;AAClC,QAAA,IAAI,EAAE,yDAAyD;AAC/D,QAAA,KAAK,EAAE,sDAAsD;AAC7D,QAAA,OAAO,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,0BAA0B,EAAE,KAAK,EAAE,wBAAwB,EAAE;AACzG,KAAA;CACF;AASD,MAAM,cAAc,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,EAA2B,KAAI;AACnI,IAAA,QACEA,IAAA,CAACC,IAAQ,EAAA,EAAA,GACH,UAAU,EACd,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,CAAC,KAAK,KACf,EAAE,CACA,oMAAoM,EACpM,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EACrB,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EACxC,CAAC,IAAI,IAAI,UAAU,CAAC,OAAO,KAAK,gBAAgB,EAChD,OAAO,SAAS,KAAK,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAC/D,EAAA,QAAA,EAAA,CAGF,gBAAgB,CAAC,IAAI,CAAC,KACrBC,GAAA,CAAC,IAAI,EAAA,EAAC,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAA,CAAI,CAC1H,EACA,cAAc,CAAC,IAAI,CAAC,IAAI,IAAI,EAE5B,QAAQ,KACPA,GAAA,CAAA,MAAA,EAAA,EACE,SAAS,EAAE,EAAE,CACX,oFAAoF,EACpF,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EACtB,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,CAC1C,YAEA,QAAQ,EAAA,CACJ,CACR,CAAA,EAAA,CACQ;AAEf,CAAC;AAeM,MAAM,cAAc,GAAG,CAAC,EAC7B,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,OAAO,EACP,SAAS,EACT,SAAS,EACT,GAAG,UAAU,EACO,KAAI;AACxB,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,kBAAkB,CAAC;AAE9C,IAAA,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM;AAC7B,IAAA,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,SAAS;AAEtC,IAAA,QACEA,GAAA,CAACC,UAAc,EAAA,EAAA,GACT,UAAU,EACd,SAAS,EAAE,EAAE,CACX,2CAA2C,EAC3C,SAAS,GAAG,kBAAkB,GAAG,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,GAAG,kBAAkB,GAAG,kBAAkB,EAClH,SAAS,CACV,EAAA,QAAA,EAEA,CAAC,EAAE,SAAS,EAAE,MACbH,IAAA,CAAAI,QAAA,EAAA,EAAA,QAAA,EAAA,CACG,SAAS,IACRJ,IAAA,CAACC,IAAQ,EAAA,EACP,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,KACvC,EAAE,CACA,mGAAmG,EACnG,CAAC,SAAS,IAAI,cAAc,KAAK,WAAW,CAC7C,EAAA,QAAA,EAAA,CAGHC,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,yEAAyE,EAAA,QAAA,EACtFA,GAAA,CAAC,MAAM,EAAA,EAAC,IAAI,EAAC,IAAI,EAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAC,WAAW,EAAC,gBAAgB,EAAC,0BAA0B,EAAA,CAAG,EAAA,CAClG,EACL,QAAQ,IAAIA,cAAM,SAAS,EAAC,oCAAoC,EAAA,QAAA,EAAE,QAAQ,EAAA,CAAQ,CAAA,EAAA,CAC1E,IACT,UAAU,IACZA,IAAC;;AAEY,kBAAA,EAAA,YAAA,EAAA,0BAA0B,EACrC,IAAI,EAAE,IAAI,KAAK,WAAW,GAAG,MAAM,GAAG,IAAI,EAC1C,OAAO,EAAE,OAAO,EAAA,QAAA,EAAA,KAAA,EAAA,CAGD,KAEjBA,GAAA,CAAC,cAAc,EAAA,EAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,KAAK,WAAW,GAAG,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,OAAO,EAAA,QAAA,EACrH,QAAQ,EAAA,CACM,CAClB,EAGA,CAAC,SAAS;AACT,qBAAC,OAAO,KAAK,OAAO,IAClBA,GAAA,CAAC,YAAY,EAAA,EAAC,SAAS,EAAC,0DAA0D,GAAG,KAErFA,GAAA,CAAC,YAAY,EAAA,EAAC,SAAS,EAAC,0DAA0D,EAAA,CAAG,CACtF,CAAC,CAAA,EAAA,CACH,CACJ,EAAA,CACc;AAErB;;;;"}
1
+ {"version":3,"file":"breadcrumb-item.js","sources":["../../../../../src/components/molecules/Breadcrumbs/components/breadcrumb-item.tsx"],"sourcesContent":[null],"names":["_jsxs","AriaLink","_jsx","AriaBreadcrumb","_Fragment"],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Reusable PostCSS scoping transform for Tailwind v4 output.
5
+ *
6
+ * Any app that ships Tailwind v4 CSS into a page it doesn't fully own — a widget, an
7
+ * embed, a Storybook preview, a multi-tenant host, or a micro-frontend — needs to scope
8
+ * its emitted selectors under a single DOM subtree so its utilities and Preflight resets
9
+ * don't leak into (or get clobbered by) the surrounding CSS.
10
+ *
11
+ * `createScopedPrefixTransform` produces the `transform` callback for
12
+ * [`postcss-prefix-selector`](https://www.npmjs.com/package/postcss-prefix-selector),
13
+ * consolidating the scoping rules every consumer would otherwise hand-copy (and drift on):
14
+ * scoping `:root`/`html` so `@theme` tokens and base typography cascade only within the
15
+ * subtree, leaving `:host` and `@keyframes` steps alone, never double-prefixing, and
16
+ * optionally scoping `body` resets or letting the scope root element match class selectors.
17
+ *
18
+ * This is a pure function with no Node or DOM dependency, so it runs cleanly inside a
19
+ * `postcss.config.mjs`.
20
+ *
21
+ * Why PostCSS (not Tailwind's own `important(#selector)`): Tailwind v4's `important(...)`
22
+ * syntax emits non-standard `@media important(...)` blocks that lightningcss can't parse
23
+ * during minification, so scoping is done as a PostCSS pass over Tailwind's output instead.
24
+ *
25
+ * @example
26
+ * ```js
27
+ * // postcss.config.mjs
28
+ * import prefixSelector from 'postcss-prefix-selector';
29
+ * import { createScopedPrefixTransform } from '@flipdish/ui-library/utilities/cssScopeUtils';
30
+ *
31
+ * const SCOPE = '#flipdish-micro-frontend';
32
+ *
33
+ * export default {
34
+ * plugins: [
35
+ * prefixSelector({
36
+ * prefix: SCOPE,
37
+ * transform: createScopedPrefixTransform(SCOPE),
38
+ * }),
39
+ * ],
40
+ * };
41
+ * ```
42
+ */
43
+ /** `@keyframes` step selectors (`from`, `to`, `0%`, `50%`, `33.33%`) — never prefixed. */
44
+ const KEYFRAME_STEP = /^(from|to|\d+(\.\d+)?%)$/;
45
+ /** Escape a string for safe use as a literal inside a `RegExp`. */
46
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
47
+ /**
48
+ * Build the `transform` callback for `postcss-prefix-selector` that scopes Tailwind v4 output
49
+ * under `scopeSelector`.
50
+ *
51
+ * @param scopeSelector The selector every rule is scoped under (e.g. `'#flipdish-micro-frontend'`
52
+ * or `'[data-tailwind]'`). Must match the `prefix` passed to `postcss-prefix-selector`.
53
+ * @param options Behavioural toggles — see {@link ScopedPrefixTransformOptions}.
54
+ * @returns A `(prefix, selector, prefixedSelector, filePath?) => string` transform.
55
+ */
56
+ function createScopedPrefixTransform(scopeSelector, options = {}) {
57
+ const { shouldScope, scopeBody = false, matchRootElement = false } = options;
58
+ const normalisedScopeSelector = scopeSelector.trim();
59
+ if (!normalisedScopeSelector) {
60
+ throw new Error('createScopedPrefixTransform: `scopeSelector` must be a non-empty selector.');
61
+ }
62
+ // Detects a selector that is already scoped, so it isn't double-prefixed. Anchored at the
63
+ // start (our scoped output always begins with the scope root) and followed by a real
64
+ // selector boundary — so a longer sibling like `#app2` / `.scope-inner`, or the scope
65
+ // string appearing inside an attribute value, is NOT mistaken for the scope `#app` / `.scope`.
66
+ const alreadyScoped = new RegExp(`^${escapeRegExp(normalisedScopeSelector)}(?=$|[\\s>+~.,:\\[#])`);
67
+ return (prefix, selector, prefixedSelector, filePath) => {
68
+ // File guard: leave non-scoped files (e.g. third-party CSS) entirely untouched.
69
+ if (shouldScope && !shouldScope(filePath)) {
70
+ return selector;
71
+ }
72
+ // Never double-prefix a selector that is already scoped (root-anchored — see above).
73
+ if (alreadyScoped.test(selector.trimStart())) {
74
+ return selector;
75
+ }
76
+ // `:root` / `html` both target the page root. Rewrite them to the scope selector so
77
+ // `@theme` tokens and Preflight base typography cascade only within the scoped subtree
78
+ // (multi-tenant-safe — sibling scopes don't clobber each other's tokens).
79
+ if (selector === ':root' || selector === 'html') {
80
+ return prefix;
81
+ }
82
+ // Shadow-host rules are already a tight scope — leave them alone.
83
+ if (selector === ':host') {
84
+ return selector;
85
+ }
86
+ // `body` resets: scope them only when opted in; otherwise leave `body` global so the
87
+ // host page keeps its own reset.
88
+ if (selector === 'body') {
89
+ return scopeBody ? prefix : selector;
90
+ }
91
+ // `@keyframes` step selectors (`from`, `to`, `50%`) must never be prefixed.
92
+ if (KEYFRAME_STEP.test(selector.trim())) {
93
+ return selector;
94
+ }
95
+ // Class selectors: optionally also match the scope root element itself via a compound
96
+ // selector (`#scope.flex-1, #scope .flex-1`), so a utility on the mount node applies too.
97
+ if (matchRootElement && selector.startsWith('.')) {
98
+ return `${prefix}${selector}, ${prefixedSelector}`;
99
+ }
100
+ // Everything else (`*`, `::before`, `::after`, `[hidden]`, element selectors, …) gets the
101
+ // standard descendant-scoped selector.
102
+ return prefixedSelector;
103
+ };
104
+ }
105
+
106
+ exports.createScopedPrefixTransform = createScopedPrefixTransform;
107
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../../src/utilities/cssScopeUtils/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCG;AA4BH;AACA,MAAM,aAAa,GAAG,0BAA0B;AAEhD;AACA,MAAM,YAAY,GAAG,CAAC,KAAa,KAAa,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC;AAE5F;;;;;;;;AAQG;SACa,2BAA2B,CACzC,aAAqB,EACrB,UAAwC,EAAE,EAAA;AAE1C,IAAA,MAAM,EAAE,WAAW,EAAE,SAAS,GAAG,KAAK,EAAE,gBAAgB,GAAG,KAAK,EAAE,GAAG,OAAO;AAE5E,IAAA,MAAM,uBAAuB,GAAG,aAAa,CAAC,IAAI,EAAE;IACpD,IAAI,CAAC,uBAAuB,EAAE;AAC5B,QAAA,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC;IAC/F;;;;;AAMA,IAAA,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,YAAY,CAAC,uBAAuB,CAAC,CAAA,qBAAA,CAAuB,CAAC;IAElG,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,KAAI;;QAEtD,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE;AACzC,YAAA,OAAO,QAAQ;QACjB;;QAGA,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE;AAC5C,YAAA,OAAO,QAAQ;QACjB;;;;QAKA,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,EAAE;AAC/C,YAAA,OAAO,MAAM;QACf;;AAGA,QAAA,IAAI,QAAQ,KAAK,OAAO,EAAE;AACxB,YAAA,OAAO,QAAQ;QACjB;;;AAIA,QAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;YACvB,OAAO,SAAS,GAAG,MAAM,GAAG,QAAQ;QACtC;;QAGA,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE;AACvC,YAAA,OAAO,QAAQ;QACjB;;;QAIA,IAAI,gBAAgB,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAChD,YAAA,OAAO,GAAG,MAAM,CAAA,EAAG,QAAQ,CAAA,EAAA,EAAK,gBAAgB,EAAE;QACpD;;;AAIA,QAAA,OAAO,gBAAgB;AACzB,IAAA,CAAC;AACH;;;;"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Reusable PostCSS scoping transform for Tailwind v4 output.
3
+ *
4
+ * Any app that ships Tailwind v4 CSS into a page it doesn't fully own — a widget, an
5
+ * embed, a Storybook preview, a multi-tenant host, or a micro-frontend — needs to scope
6
+ * its emitted selectors under a single DOM subtree so its utilities and Preflight resets
7
+ * don't leak into (or get clobbered by) the surrounding CSS.
8
+ *
9
+ * `createScopedPrefixTransform` produces the `transform` callback for
10
+ * [`postcss-prefix-selector`](https://www.npmjs.com/package/postcss-prefix-selector),
11
+ * consolidating the scoping rules every consumer would otherwise hand-copy (and drift on):
12
+ * scoping `:root`/`html` so `@theme` tokens and base typography cascade only within the
13
+ * subtree, leaving `:host` and `@keyframes` steps alone, never double-prefixing, and
14
+ * optionally scoping `body` resets or letting the scope root element match class selectors.
15
+ *
16
+ * This is a pure function with no Node or DOM dependency, so it runs cleanly inside a
17
+ * `postcss.config.mjs`.
18
+ *
19
+ * Why PostCSS (not Tailwind's own `important(#selector)`): Tailwind v4's `important(...)`
20
+ * syntax emits non-standard `@media important(...)` blocks that lightningcss can't parse
21
+ * during minification, so scoping is done as a PostCSS pass over Tailwind's output instead.
22
+ *
23
+ * @example
24
+ * ```js
25
+ * // postcss.config.mjs
26
+ * import prefixSelector from 'postcss-prefix-selector';
27
+ * import { createScopedPrefixTransform } from '@flipdish/ui-library/utilities/cssScopeUtils';
28
+ *
29
+ * const SCOPE = '#flipdish-micro-frontend';
30
+ *
31
+ * export default {
32
+ * plugins: [
33
+ * prefixSelector({
34
+ * prefix: SCOPE,
35
+ * transform: createScopedPrefixTransform(SCOPE),
36
+ * }),
37
+ * ],
38
+ * };
39
+ * ```
40
+ */
41
+ export interface ScopedPrefixTransformOptions {
42
+ /**
43
+ * Predicate deciding which files get scoped. Return `false` to leave a file's selectors
44
+ * untouched (e.g. third-party CSS that already ships its own scoping). The transform is
45
+ * called once per selector with the source file path, so this lets you skip whole files.
46
+ *
47
+ * @default () => true (scope everything through the pipeline)
48
+ */
49
+ shouldScope?: (filePath: string | undefined) => boolean;
50
+ /**
51
+ * Scope Preflight `body` resets to the mount selector instead of leaving `body` global.
52
+ * Enable this when the surrounding page must not inherit Tailwind's `body` reset.
53
+ *
54
+ * @default false
55
+ */
56
+ scopeBody?: boolean;
57
+ /**
58
+ * Also emit a compound selector so the scope root element itself matches class selectors
59
+ * (e.g. `<div data-scope class="flex-1">` — where the utility must apply to the mount node,
60
+ * not just its descendants).
61
+ *
62
+ * @default false
63
+ */
64
+ matchRootElement?: boolean;
65
+ }
66
+ /**
67
+ * Build the `transform` callback for `postcss-prefix-selector` that scopes Tailwind v4 output
68
+ * under `scopeSelector`.
69
+ *
70
+ * @param scopeSelector The selector every rule is scoped under (e.g. `'#flipdish-micro-frontend'`
71
+ * or `'[data-tailwind]'`). Must match the `prefix` passed to `postcss-prefix-selector`.
72
+ * @param options Behavioural toggles — see {@link ScopedPrefixTransformOptions}.
73
+ * @returns A `(prefix, selector, prefixedSelector, filePath?) => string` transform.
74
+ */
75
+ export declare function createScopedPrefixTransform(scopeSelector: string, options?: ScopedPrefixTransformOptions): (prefix: string, selector: string, prefixedSelector: string, filePath?: string) => string;
76
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utilities/cssScopeUtils/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,MAAM,WAAW,4BAA4B;IAC3C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC;IACxD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAQD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,4BAAiC,GACzC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CA0D3F"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Reusable PostCSS scoping transform for Tailwind v4 output.
3
+ *
4
+ * Any app that ships Tailwind v4 CSS into a page it doesn't fully own — a widget, an
5
+ * embed, a Storybook preview, a multi-tenant host, or a micro-frontend — needs to scope
6
+ * its emitted selectors under a single DOM subtree so its utilities and Preflight resets
7
+ * don't leak into (or get clobbered by) the surrounding CSS.
8
+ *
9
+ * `createScopedPrefixTransform` produces the `transform` callback for
10
+ * [`postcss-prefix-selector`](https://www.npmjs.com/package/postcss-prefix-selector),
11
+ * consolidating the scoping rules every consumer would otherwise hand-copy (and drift on):
12
+ * scoping `:root`/`html` so `@theme` tokens and base typography cascade only within the
13
+ * subtree, leaving `:host` and `@keyframes` steps alone, never double-prefixing, and
14
+ * optionally scoping `body` resets or letting the scope root element match class selectors.
15
+ *
16
+ * This is a pure function with no Node or DOM dependency, so it runs cleanly inside a
17
+ * `postcss.config.mjs`.
18
+ *
19
+ * Why PostCSS (not Tailwind's own `important(#selector)`): Tailwind v4's `important(...)`
20
+ * syntax emits non-standard `@media important(...)` blocks that lightningcss can't parse
21
+ * during minification, so scoping is done as a PostCSS pass over Tailwind's output instead.
22
+ *
23
+ * @example
24
+ * ```js
25
+ * // postcss.config.mjs
26
+ * import prefixSelector from 'postcss-prefix-selector';
27
+ * import { createScopedPrefixTransform } from '@flipdish/ui-library/utilities/cssScopeUtils';
28
+ *
29
+ * const SCOPE = '#flipdish-micro-frontend';
30
+ *
31
+ * export default {
32
+ * plugins: [
33
+ * prefixSelector({
34
+ * prefix: SCOPE,
35
+ * transform: createScopedPrefixTransform(SCOPE),
36
+ * }),
37
+ * ],
38
+ * };
39
+ * ```
40
+ */
41
+ /** `@keyframes` step selectors (`from`, `to`, `0%`, `50%`, `33.33%`) — never prefixed. */
42
+ const KEYFRAME_STEP = /^(from|to|\d+(\.\d+)?%)$/;
43
+ /** Escape a string for safe use as a literal inside a `RegExp`. */
44
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
45
+ /**
46
+ * Build the `transform` callback for `postcss-prefix-selector` that scopes Tailwind v4 output
47
+ * under `scopeSelector`.
48
+ *
49
+ * @param scopeSelector The selector every rule is scoped under (e.g. `'#flipdish-micro-frontend'`
50
+ * or `'[data-tailwind]'`). Must match the `prefix` passed to `postcss-prefix-selector`.
51
+ * @param options Behavioural toggles — see {@link ScopedPrefixTransformOptions}.
52
+ * @returns A `(prefix, selector, prefixedSelector, filePath?) => string` transform.
53
+ */
54
+ function createScopedPrefixTransform(scopeSelector, options = {}) {
55
+ const { shouldScope, scopeBody = false, matchRootElement = false } = options;
56
+ const normalisedScopeSelector = scopeSelector.trim();
57
+ if (!normalisedScopeSelector) {
58
+ throw new Error('createScopedPrefixTransform: `scopeSelector` must be a non-empty selector.');
59
+ }
60
+ // Detects a selector that is already scoped, so it isn't double-prefixed. Anchored at the
61
+ // start (our scoped output always begins with the scope root) and followed by a real
62
+ // selector boundary — so a longer sibling like `#app2` / `.scope-inner`, or the scope
63
+ // string appearing inside an attribute value, is NOT mistaken for the scope `#app` / `.scope`.
64
+ const alreadyScoped = new RegExp(`^${escapeRegExp(normalisedScopeSelector)}(?=$|[\\s>+~.,:\\[#])`);
65
+ return (prefix, selector, prefixedSelector, filePath) => {
66
+ // File guard: leave non-scoped files (e.g. third-party CSS) entirely untouched.
67
+ if (shouldScope && !shouldScope(filePath)) {
68
+ return selector;
69
+ }
70
+ // Never double-prefix a selector that is already scoped (root-anchored — see above).
71
+ if (alreadyScoped.test(selector.trimStart())) {
72
+ return selector;
73
+ }
74
+ // `:root` / `html` both target the page root. Rewrite them to the scope selector so
75
+ // `@theme` tokens and Preflight base typography cascade only within the scoped subtree
76
+ // (multi-tenant-safe — sibling scopes don't clobber each other's tokens).
77
+ if (selector === ':root' || selector === 'html') {
78
+ return prefix;
79
+ }
80
+ // Shadow-host rules are already a tight scope — leave them alone.
81
+ if (selector === ':host') {
82
+ return selector;
83
+ }
84
+ // `body` resets: scope them only when opted in; otherwise leave `body` global so the
85
+ // host page keeps its own reset.
86
+ if (selector === 'body') {
87
+ return scopeBody ? prefix : selector;
88
+ }
89
+ // `@keyframes` step selectors (`from`, `to`, `50%`) must never be prefixed.
90
+ if (KEYFRAME_STEP.test(selector.trim())) {
91
+ return selector;
92
+ }
93
+ // Class selectors: optionally also match the scope root element itself via a compound
94
+ // selector (`#scope.flex-1, #scope .flex-1`), so a utility on the mount node applies too.
95
+ if (matchRootElement && selector.startsWith('.')) {
96
+ return `${prefix}${selector}, ${prefixedSelector}`;
97
+ }
98
+ // Everything else (`*`, `::before`, `::after`, `[hidden]`, element selectors, …) gets the
99
+ // standard descendant-scoped selector.
100
+ return prefixedSelector;
101
+ };
102
+ }
103
+
104
+ export { createScopedPrefixTransform };
105
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../src/utilities/cssScopeUtils/index.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCG;AA4BH;AACA,MAAM,aAAa,GAAG,0BAA0B;AAEhD;AACA,MAAM,YAAY,GAAG,CAAC,KAAa,KAAa,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC;AAE5F;;;;;;;;AAQG;SACa,2BAA2B,CACzC,aAAqB,EACrB,UAAwC,EAAE,EAAA;AAE1C,IAAA,MAAM,EAAE,WAAW,EAAE,SAAS,GAAG,KAAK,EAAE,gBAAgB,GAAG,KAAK,EAAE,GAAG,OAAO;AAE5E,IAAA,MAAM,uBAAuB,GAAG,aAAa,CAAC,IAAI,EAAE;IACpD,IAAI,CAAC,uBAAuB,EAAE;AAC5B,QAAA,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC;IAC/F;;;;;AAMA,IAAA,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,CAAA,CAAA,EAAI,YAAY,CAAC,uBAAuB,CAAC,CAAA,qBAAA,CAAuB,CAAC;IAElG,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,KAAI;;QAEtD,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE;AACzC,YAAA,OAAO,QAAQ;QACjB;;QAGA,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE;AAC5C,YAAA,OAAO,QAAQ;QACjB;;;;QAKA,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,EAAE;AAC/C,YAAA,OAAO,MAAM;QACf;;AAGA,QAAA,IAAI,QAAQ,KAAK,OAAO,EAAE;AACxB,YAAA,OAAO,QAAQ;QACjB;;;AAIA,QAAA,IAAI,QAAQ,KAAK,MAAM,EAAE;YACvB,OAAO,SAAS,GAAG,MAAM,GAAG,QAAQ;QACtC;;QAGA,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE;AACvC,YAAA,OAAO,QAAQ;QACjB;;;QAIA,IAAI,gBAAgB,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;AAChD,YAAA,OAAO,GAAG,MAAM,CAAA,EAAG,QAAQ,CAAA,EAAA,EAAK,gBAAgB,EAAE;QACpD;;;AAIA,QAAA,OAAO,gBAAgB;AACzB,IAAA,CAAC;AACH;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flipdish/ui-library",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "Flipdish Design System — atomic-design component library (Tailwind v4 + UntitledUI + React Aria).",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -85,6 +85,7 @@
85
85
  "input-otp": "^1.4.2",
86
86
  "motion": "^12.40.0",
87
87
  "nativewind": "^4.1.0",
88
+ "postcss-prefix-selector": "^2.1.1",
88
89
  "qr-code-styling": "^1.9.2",
89
90
  "react": "^19.0.0",
90
91
  "react-aria-components": "^1.18.0",
@@ -143,6 +144,9 @@
143
144
  "nativewind": {
144
145
  "optional": true
145
146
  },
147
+ "postcss-prefix-selector": {
148
+ "optional": true
149
+ },
146
150
  "qr-code-styling": {
147
151
  "optional": true
148
152
  },
@@ -172,6 +176,7 @@
172
176
  "@figma/code-connect": "^1.4.8",
173
177
  "@storybook/addon-a11y": "^10.4.6",
174
178
  "@storybook/addon-docs": "^10.4.6",
179
+ "@storybook/addon-mcp": "^0.6.0",
175
180
  "@storybook/react-vite": "^10.4.6",
176
181
  "@tailwindcss/vite": "^4.3.1",
177
182
  "@tiptap/core": "^3.27.1",
@@ -209,7 +214,7 @@
209
214
  "scripts": {
210
215
  "build": "rollup -c && tsc -p tsconfig.build.json",
211
216
  "typecheck": "tsc --noEmit",
212
- "test": "echo 'No tests yet'",
217
+ "test": "node --test \"src/**/*.test.ts\"",
213
218
  "typecheck:native": "tsc --noEmit -p tsconfig.native.json",
214
219
  "storybook": "storybook dev -p 6006",
215
220
  "build-storybook": "storybook build",