@krizaka/ui 3.40.0 → 3.41.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.
package/dist/flock.d.ts CHANGED
@@ -28,6 +28,12 @@ type FlockProps = Omit<React.ComponentProps<"div">, "children"> & FlockMoments &
28
28
  tone?: "brand" | "own";
29
29
  /** The source of chance (default `Math.random`): give it a fixed one in a test. */
30
30
  random?: () => number;
31
+ /** How lively the moments are: 1 is calm (default), 2 doubles how often neighbours glance and the pigeon delivers. */
32
+ tempo?: number;
33
+ /** A bird the page points at (a product the reader is on): it looks up and jumps once each time it changes. */
34
+ active?: MascotBird | null;
35
+ /** The birds greet the reader once as the flock first comes into view: each jumps in turn, left to right. */
36
+ greet?: boolean;
31
37
  };
32
38
  /**
33
39
  * The flock on its stage, alive. Decorative (`aria-hidden`): put the words beside it. Each bird idles in character; every
@@ -35,6 +41,6 @@ type FlockProps = Omit<React.ComponentProps<"div">, "children"> & FlockMoments &
35
41
  * returns; a bird looks up when you come near. All of it pauses off screen and in a hidden tab, and the flock is still
36
42
  * under `prefers-reduced-motion`.
37
43
  */
38
- declare function Flock({ birds, ratio, tone, glance, courier, react, random, className, style, ...props }: FlockProps): React.JSX.Element;
44
+ declare function Flock({ birds, ratio, tone, glance, courier, react, random, tempo, active, greet, className, style, ...props }: FlockProps): React.JSX.Element;
39
45
 
40
46
  export { Flock, type FlockBird, type FlockMoments, type FlockProps };
package/dist/flock.js CHANGED
@@ -16,7 +16,9 @@ var COURIER_EVERY_MS = [26e3, 38e3];
16
16
  var FLIGHT_MS = 2600;
17
17
  var HAND_OVER_MS = 1300;
18
18
  var LOOK_BACK_MS = 1600;
19
- var between = (random, [lo, hi]) => lo + random() * (hi - lo);
19
+ var between = (random, [lo, hi], tempo = 1) => (lo + random() * (hi - lo)) / tempo;
20
+ var GREET_STEP_MS = 110;
21
+ var POKE_MS = 700;
20
22
  function useMayMove() {
21
23
  const [may, setMay] = React.useState(false);
22
24
  React.useEffect(() => {
@@ -43,7 +45,7 @@ function useOnScreen(ref) {
43
45
  }, [ref]);
44
46
  return on;
45
47
  }
46
- function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier = true, react = true, random = Math.random, className, style, ...props }) {
48
+ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier = true, react = true, random = Math.random, tempo = 1, active = null, greet = false, className, style, ...props }) {
47
49
  const stage = React.useRef(null);
48
50
  const bodies = React.useRef([]);
49
51
  const may = useMayMove();
@@ -69,14 +71,14 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
69
71
  rest(a, b);
70
72
  next();
71
73
  }, between(random, GLANCE_HOLD_MS));
72
- }, between(random, GLANCE_EVERY_MS));
74
+ }, between(random, GLANCE_EVERY_MS, tempo));
73
75
  };
74
76
  next();
75
77
  return () => {
76
78
  clearTimeout(timer);
77
79
  clearTimeout(back);
78
80
  };
79
- }, [running, glance, order, random]);
81
+ }, [running, glance, order, random, tempo]);
80
82
  React.useEffect(() => {
81
83
  const pigeon = birds.findIndex((b) => b.bird === "pigeon");
82
84
  if (!running || !courier || pigeon < 0 || birds.length < 2) return;
@@ -122,17 +124,43 @@ function Flock({ birds, ratio = 16 / 9, tone = "brand", glance = true, courier =
122
124
  const schedule = (ms) => {
123
125
  timer = setTimeout(async () => {
124
126
  await trip();
125
- if (alive) schedule(between(random, COURIER_EVERY_MS));
127
+ if (alive) schedule(between(random, COURIER_EVERY_MS, tempo));
126
128
  }, ms);
127
129
  };
128
- schedule(COURIER_FIRST_MS);
130
+ schedule(COURIER_FIRST_MS / tempo);
129
131
  return () => {
130
132
  alive = false;
131
133
  clearTimeout(timer);
132
134
  animation?.cancel();
133
135
  setFlying(null);
134
136
  };
135
- }, [running, courier, birds, random]);
137
+ }, [running, courier, birds, random, tempo]);
138
+ const greeted = React.useRef(false);
139
+ React.useEffect(() => {
140
+ if (!running || !greet || greeted.current) return;
141
+ greeted.current = true;
142
+ const timers = [];
143
+ order.forEach((index, n) => {
144
+ timers.push(setTimeout(() => setPoked((p) => ({ ...p, [index]: true })), n * GREET_STEP_MS));
145
+ timers.push(setTimeout(() => setPoked((p) => ({ ...p, [index]: false })), n * GREET_STEP_MS + POKE_MS));
146
+ });
147
+ return () => timers.forEach(clearTimeout);
148
+ }, [running, greet, order]);
149
+ React.useEffect(() => {
150
+ const index = active ? birds.findIndex((b) => b.bird === active) : -1;
151
+ if (!running || index < 0) return;
152
+ const start = setTimeout(() => {
153
+ look(index, "up");
154
+ setPoked((p) => ({ ...p, [index]: true }));
155
+ }, 0);
156
+ const t = setTimeout(() => setPoked((p) => ({ ...p, [index]: false })), POKE_MS);
157
+ return () => {
158
+ clearTimeout(start);
159
+ clearTimeout(t);
160
+ setPoked((p) => ({ ...p, [index]: false }));
161
+ rest(index);
162
+ };
163
+ }, [active, running, birds]);
136
164
  const hover = (index, event) => {
137
165
  if (!running || !react || event.pointerType !== "mouse") return;
138
166
  look(index, "up");
package/dist/flock.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/flock/flock.tsx"],"sourcesContent":["\"use client\";\n\n// The flock, alive: birds standing on a stage, each at ease in character (Mascot `life`), and the moments between\n// them — two birds glance at each other, the pigeon carries its parcel across, a bird looks up when you come near or tap\n// it. Transform and opacity only: CSS for each bird's own life, a timer for the moments (no frame loop), and nothing at\n// all when the flock is off screen, the tab is hidden or the person asked for less motion.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport type { MascotBird, MascotLook } from \"../mascots\";\nimport { Mascot } from \"../mascots\";\n\nexport interface FlockBird {\n /** Which bird. */\n bird: MascotBird;\n /** Where its feet are, across the stage: 0 to 100 (% of the stage's width). */\n x: number;\n /** Where its feet are, down the stage: 0 to 100 (% of the stage's height). */\n y: number;\n /** How wide it is: % of the stage's width. */\n size: number;\n}\n\nexport interface FlockMoments {\n /** Two neighbours look at each other now and then. Default `true`. */\n glance?: boolean;\n /** The pigeon, when the flock has one, carries its parcel across to another bird and comes back. Default `true`. */\n courier?: boolean;\n /** A bird looks up when the pointer comes near, and jumps a little when tapped. Default `true`. */\n react?: boolean;\n}\n\nexport type FlockProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n FlockMoments & {\n /** The birds on the stage. */\n birds: readonly FlockBird[];\n /** The stage's shape, width over height (default 16 / 9). It keeps its ratio at any width, so the birds keep their places. */\n ratio?: number;\n /** The birds' colours: the host's accent (`brand`, default) or the Krizaka story's (`own`). */\n tone?: \"brand\" | \"own\";\n /** The source of chance (default `Math.random`): give it a fixed one in a test. */\n random?: () => number;\n };\n\n// @fixed: the rhythm of the moments — how long a glance lasts, how often one happens, how long a delivery takes. A\n// choreography's pace, not a business parameter.\nconst GLANCE_HOLD_MS = [1500, 2400] as const;\nconst GLANCE_EVERY_MS = [4200, 9000] as const;\nconst COURIER_FIRST_MS = 9000;\nconst COURIER_EVERY_MS = [26000, 38000] as const;\nconst FLIGHT_MS = 2600;\nconst HAND_OVER_MS = 1300;\nconst LOOK_BACK_MS = 1600;\n\nconst between = (random: () => number, [lo, hi]: readonly [number, number]) => lo + random() * (hi - lo);\n\n/** `true` while the page may move: no reduced-motion request, the tab visible. */\nfunction useMayMove(): boolean {\n const [may, setMay] = React.useState(false);\n React.useEffect(() => {\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const update = () => setMay(!query.matches && document.visibilityState !== \"hidden\");\n update();\n query.addEventListener(\"change\", update);\n document.addEventListener(\"visibilitychange\", update);\n return () => {\n query.removeEventListener(\"change\", update);\n document.removeEventListener(\"visibilitychange\", update);\n };\n }, []);\n return may;\n}\n\n/** `true` while the element is on screen. */\nfunction useOnScreen(ref: React.RefObject<Element | null>): boolean {\n const [on, setOn] = React.useState(false);\n React.useEffect(() => {\n const el = ref.current;\n if (!el || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => setOn(Boolean(entry?.isIntersecting)), { threshold: 0.1 });\n observer.observe(el);\n return () => observer.disconnect();\n }, [ref]);\n return on;\n}\n\n/**\n * The flock on its stage, alive. Decorative (`aria-hidden`): put the words beside it. Each bird idles in character; every\n * few seconds two neighbours glance at each other; every half minute the pigeon carries its parcel to another bird and\n * returns; a bird looks up when you come near. All of it pauses off screen and in a hidden tab, and the flock is still\n * under `prefers-reduced-motion`.\n */\nexport function Flock({ birds, ratio = 16 / 9, tone = \"brand\", glance = true, courier = true, react = true, random = Math.random, className, style, ...props }: FlockProps) {\n const stage = React.useRef<HTMLDivElement>(null);\n const bodies = React.useRef<(HTMLDivElement | null)[]>([]);\n const may = useMayMove();\n const onScreen = useOnScreen(stage);\n const running = may && onScreen;\n const [looks, setLooks] = React.useState<Record<number, MascotLook>>({});\n const [flying, setFlying] = React.useState<{ index: number; bank: number } | null>(null);\n const [poked, setPoked] = React.useState<Record<number, boolean>>({});\n\n // Left to right: a bird's neighbours are the birds beside it on the stage.\n const order = React.useMemo(() => birds.map((_, i) => i).sort((a, b) => birds[a]!.x - birds[b]!.x), [birds]);\n const look = (index: number, to: MascotLook) => setLooks((l) => (l[index] === to ? l : { ...l, [index]: to }));\n const rest = (...indexes: number[]) => setLooks((l) => Object.fromEntries(Object.entries(l).filter(([k]) => !indexes.includes(Number(k)))));\n\n // Glances: two neighbours turn towards each other, hold, and look away.\n React.useEffect(() => {\n if (!running || !glance || order.length < 2) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let back: ReturnType<typeof setTimeout> | undefined;\n const next = () => {\n timer = setTimeout(() => {\n const at = Math.floor(random() * (order.length - 1));\n const [a, b] = [order[at]!, order[at + 1]!];\n look(a, \"right\");\n look(b, \"left\");\n back = setTimeout(() => {\n rest(a, b);\n next();\n }, between(random, GLANCE_HOLD_MS));\n }, between(random, GLANCE_EVERY_MS));\n };\n next();\n return () => {\n clearTimeout(timer);\n clearTimeout(back);\n };\n }, [running, glance, order, random]);\n\n // The delivery: the pigeon takes its parcel across to the farthest bird, hands it over, and flies back.\n React.useEffect(() => {\n const pigeon = birds.findIndex((b) => b.bird === \"pigeon\");\n if (!running || !courier || pigeon < 0 || birds.length < 2) return;\n let alive = true;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let animation: Animation | undefined;\n const wait = (ms: number) => new Promise<void>((resolve) => (timer = setTimeout(resolve, ms)));\n const trip = async () => {\n const el = bodies.current[pigeon];\n const box = stage.current?.getBoundingClientRect();\n if (!el || !box || typeof el.animate !== \"function\") return;\n // The farthest bird from the pigeon, so the parcel crosses the whole stage.\n const from = birds[pigeon]!;\n const target = birds.reduce((far, b, i) => (i !== pigeon && Math.abs(b.x - from.x) > Math.abs(birds[far]!.x - from.x) ? i : far), pigeon === 0 ? 1 : 0);\n const to = birds[target]!;\n const side = to.x > from.x ? 1 : -1;\n // It lands beside the receiver, not on it.\n const dx = ((to.x - from.x) / 100) * box.width - side * (to.size / 100) * box.width * 0.55;\n const lift = (from.size / 100) * box.width * 0.35;\n const fly = async (fromX: number, toX: number) => {\n setFlying({ index: pigeon, bank: Math.sign(toX - fromX) });\n animation = el.animate(\n [\n { transform: `translate(${fromX}px, 0)`, easing: \"ease-out\" },\n { transform: `translate(${(fromX + toX) / 2}px, ${-lift}px)`, easing: \"ease-in\", offset: 0.5 },\n { transform: `translate(${toX}px, 0)` },\n ],\n { duration: FLIGHT_MS, fill: \"forwards\" },\n );\n await animation.finished.catch(() => undefined);\n setFlying(null);\n };\n look(target, side > 0 ? \"left\" : \"right\");\n await fly(0, dx);\n if (!alive) return;\n // The hand-over: the receiver looks at the pigeon, the pigeon hops on the doorstep.\n setPoked((p) => ({ ...p, [pigeon]: true }));\n await wait(HAND_OVER_MS);\n if (!alive) return;\n setPoked((p) => ({ ...p, [pigeon]: false }));\n look(target, \"up\");\n await fly(dx, 0);\n animation?.cancel();\n rest(target);\n };\n const schedule = (ms: number) => {\n timer = setTimeout(async () => {\n await trip();\n if (alive) schedule(between(random, COURIER_EVERY_MS));\n }, ms);\n };\n schedule(COURIER_FIRST_MS);\n return () => {\n alive = false;\n clearTimeout(timer);\n animation?.cancel();\n setFlying(null);\n };\n }, [running, courier, birds, random]);\n\n // A bird looks up when you come near, and jumps when you tap it.\n const hover = (index: number, event: React.PointerEvent) => {\n if (!running || !react || event.pointerType !== \"mouse\") return;\n look(index, \"up\");\n };\n const leave = (index: number) => {\n if (!react) return;\n rest(index);\n };\n const tap = (index: number) => {\n if (!running || !react) return;\n look(index, \"up\");\n setPoked((p) => ({ ...p, [index]: true }));\n setTimeout(() => {\n setPoked((p) => ({ ...p, [index]: false }));\n rest(index);\n }, LOOK_BACK_MS);\n };\n\n return (\n <div\n ref={stage}\n aria-hidden\n data-flock=\"\"\n data-running={running ? \"\" : undefined}\n className={cn(\"relative w-full\", className)}\n style={{ aspectRatio: String(ratio), containerType: \"inline-size\", ...style }}\n {...props}\n >\n {birds.map((b, i) => (\n <div\n key={`${b.bird}-${i}`}\n ref={(el) => {\n bodies.current[i] = el;\n }}\n data-flock-bird={b.bird}\n className=\"absolute touch-manipulation\"\n style={{ left: `${b.x - b.size / 2}%`, width: `${b.size}%`, top: `calc(${b.y}% - ${b.size * 0.9}cqw)`, aspectRatio: \"1\", pointerEvents: react ? \"auto\" : \"none\" }}\n onPointerEnter={(event) => hover(i, event)}\n onPointerLeave={() => leave(i)}\n onPointerDown={() => tap(i)}\n >\n <Mascot\n bird={b.bird}\n tone={tone}\n life\n look={looks[i]}\n flying={flying?.index === i}\n bank={flying?.index === i ? flying.bank : 0}\n poked={poked[i]}\n size={120}\n style={{ width: \"100%\", height: \"100%\", display: \"block\", overflow: \"visible\" }}\n />\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/flock/flock.tsx"],"sourcesContent":["\"use client\";\n\n// The flock, alive: birds standing on a stage, each at ease in character (Mascot `life`), and the moments between\n// them — two birds glance at each other, the pigeon carries its parcel across, a bird looks up when you come near or tap\n// it. Transform and opacity only: CSS for each bird's own life, a timer for the moments (no frame loop), and nothing at\n// all when the flock is off screen, the tab is hidden or the person asked for less motion.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport type { MascotBird, MascotLook } from \"../mascots\";\nimport { Mascot } from \"../mascots\";\n\nexport interface FlockBird {\n /** Which bird. */\n bird: MascotBird;\n /** Where its feet are, across the stage: 0 to 100 (% of the stage's width). */\n x: number;\n /** Where its feet are, down the stage: 0 to 100 (% of the stage's height). */\n y: number;\n /** How wide it is: % of the stage's width. */\n size: number;\n}\n\nexport interface FlockMoments {\n /** Two neighbours look at each other now and then. Default `true`. */\n glance?: boolean;\n /** The pigeon, when the flock has one, carries its parcel across to another bird and comes back. Default `true`. */\n courier?: boolean;\n /** A bird looks up when the pointer comes near, and jumps a little when tapped. Default `true`. */\n react?: boolean;\n}\n\nexport type FlockProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n FlockMoments & {\n /** The birds on the stage. */\n birds: readonly FlockBird[];\n /** The stage's shape, width over height (default 16 / 9). It keeps its ratio at any width, so the birds keep their places. */\n ratio?: number;\n /** The birds' colours: the host's accent (`brand`, default) or the Krizaka story's (`own`). */\n tone?: \"brand\" | \"own\";\n /** The source of chance (default `Math.random`): give it a fixed one in a test. */\n random?: () => number;\n /** How lively the moments are: 1 is calm (default), 2 doubles how often neighbours glance and the pigeon delivers. */\n tempo?: number;\n /** A bird the page points at (a product the reader is on): it looks up and jumps once each time it changes. */\n active?: MascotBird | null;\n /** The birds greet the reader once as the flock first comes into view: each jumps in turn, left to right. */\n greet?: boolean;\n };\n\n// @fixed: the rhythm of the moments — how long a glance lasts, how often one happens, how long a delivery takes. A\n// choreography's pace, not a business parameter.\nconst GLANCE_HOLD_MS = [1500, 2400] as const;\nconst GLANCE_EVERY_MS = [4200, 9000] as const;\nconst COURIER_FIRST_MS = 9000;\nconst COURIER_EVERY_MS = [26000, 38000] as const;\nconst FLIGHT_MS = 2600;\nconst HAND_OVER_MS = 1300;\nconst LOOK_BACK_MS = 1600;\n\nconst between = (random: () => number, [lo, hi]: readonly [number, number], tempo = 1) => (lo + random() * (hi - lo)) / tempo;\nconst GREET_STEP_MS = 110;\nconst POKE_MS = 700;\n\n/** `true` while the page may move: no reduced-motion request, the tab visible. */\nfunction useMayMove(): boolean {\n const [may, setMay] = React.useState(false);\n React.useEffect(() => {\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const update = () => setMay(!query.matches && document.visibilityState !== \"hidden\");\n update();\n query.addEventListener(\"change\", update);\n document.addEventListener(\"visibilitychange\", update);\n return () => {\n query.removeEventListener(\"change\", update);\n document.removeEventListener(\"visibilitychange\", update);\n };\n }, []);\n return may;\n}\n\n/** `true` while the element is on screen. */\nfunction useOnScreen(ref: React.RefObject<Element | null>): boolean {\n const [on, setOn] = React.useState(false);\n React.useEffect(() => {\n const el = ref.current;\n if (!el || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => setOn(Boolean(entry?.isIntersecting)), { threshold: 0.1 });\n observer.observe(el);\n return () => observer.disconnect();\n }, [ref]);\n return on;\n}\n\n/**\n * The flock on its stage, alive. Decorative (`aria-hidden`): put the words beside it. Each bird idles in character; every\n * few seconds two neighbours glance at each other; every half minute the pigeon carries its parcel to another bird and\n * returns; a bird looks up when you come near. All of it pauses off screen and in a hidden tab, and the flock is still\n * under `prefers-reduced-motion`.\n */\nexport function Flock({ birds, ratio = 16 / 9, tone = \"brand\", glance = true, courier = true, react = true, random = Math.random, tempo = 1, active = null, greet = false, className, style, ...props }: FlockProps) {\n const stage = React.useRef<HTMLDivElement>(null);\n const bodies = React.useRef<(HTMLDivElement | null)[]>([]);\n const may = useMayMove();\n const onScreen = useOnScreen(stage);\n const running = may && onScreen;\n const [looks, setLooks] = React.useState<Record<number, MascotLook>>({});\n const [flying, setFlying] = React.useState<{ index: number; bank: number } | null>(null);\n const [poked, setPoked] = React.useState<Record<number, boolean>>({});\n\n // Left to right: a bird's neighbours are the birds beside it on the stage.\n const order = React.useMemo(() => birds.map((_, i) => i).sort((a, b) => birds[a]!.x - birds[b]!.x), [birds]);\n const look = (index: number, to: MascotLook) => setLooks((l) => (l[index] === to ? l : { ...l, [index]: to }));\n const rest = (...indexes: number[]) => setLooks((l) => Object.fromEntries(Object.entries(l).filter(([k]) => !indexes.includes(Number(k)))));\n\n // Glances: two neighbours turn towards each other, hold, and look away.\n React.useEffect(() => {\n if (!running || !glance || order.length < 2) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let back: ReturnType<typeof setTimeout> | undefined;\n const next = () => {\n timer = setTimeout(() => {\n const at = Math.floor(random() * (order.length - 1));\n const [a, b] = [order[at]!, order[at + 1]!];\n look(a, \"right\");\n look(b, \"left\");\n back = setTimeout(() => {\n rest(a, b);\n next();\n }, between(random, GLANCE_HOLD_MS));\n }, between(random, GLANCE_EVERY_MS, tempo));\n };\n next();\n return () => {\n clearTimeout(timer);\n clearTimeout(back);\n };\n }, [running, glance, order, random, tempo]);\n\n // The delivery: the pigeon takes its parcel across to the farthest bird, hands it over, and flies back.\n React.useEffect(() => {\n const pigeon = birds.findIndex((b) => b.bird === \"pigeon\");\n if (!running || !courier || pigeon < 0 || birds.length < 2) return;\n let alive = true;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let animation: Animation | undefined;\n const wait = (ms: number) => new Promise<void>((resolve) => (timer = setTimeout(resolve, ms)));\n const trip = async () => {\n const el = bodies.current[pigeon];\n const box = stage.current?.getBoundingClientRect();\n if (!el || !box || typeof el.animate !== \"function\") return;\n // The farthest bird from the pigeon, so the parcel crosses the whole stage.\n const from = birds[pigeon]!;\n const target = birds.reduce((far, b, i) => (i !== pigeon && Math.abs(b.x - from.x) > Math.abs(birds[far]!.x - from.x) ? i : far), pigeon === 0 ? 1 : 0);\n const to = birds[target]!;\n const side = to.x > from.x ? 1 : -1;\n // It lands beside the receiver, not on it.\n const dx = ((to.x - from.x) / 100) * box.width - side * (to.size / 100) * box.width * 0.55;\n const lift = (from.size / 100) * box.width * 0.35;\n const fly = async (fromX: number, toX: number) => {\n setFlying({ index: pigeon, bank: Math.sign(toX - fromX) });\n animation = el.animate(\n [\n { transform: `translate(${fromX}px, 0)`, easing: \"ease-out\" },\n { transform: `translate(${(fromX + toX) / 2}px, ${-lift}px)`, easing: \"ease-in\", offset: 0.5 },\n { transform: `translate(${toX}px, 0)` },\n ],\n { duration: FLIGHT_MS, fill: \"forwards\" },\n );\n await animation.finished.catch(() => undefined);\n setFlying(null);\n };\n look(target, side > 0 ? \"left\" : \"right\");\n await fly(0, dx);\n if (!alive) return;\n // The hand-over: the receiver looks at the pigeon, the pigeon hops on the doorstep.\n setPoked((p) => ({ ...p, [pigeon]: true }));\n await wait(HAND_OVER_MS);\n if (!alive) return;\n setPoked((p) => ({ ...p, [pigeon]: false }));\n look(target, \"up\");\n await fly(dx, 0);\n animation?.cancel();\n rest(target);\n };\n const schedule = (ms: number) => {\n timer = setTimeout(async () => {\n await trip();\n if (alive) schedule(between(random, COURIER_EVERY_MS, tempo));\n }, ms);\n };\n schedule(COURIER_FIRST_MS / tempo);\n return () => {\n alive = false;\n clearTimeout(timer);\n animation?.cancel();\n setFlying(null);\n };\n }, [running, courier, birds, random, tempo]);\n\n // The greeting: the first time the flock is on screen, each bird jumps in turn.\n const greeted = React.useRef(false);\n React.useEffect(() => {\n if (!running || !greet || greeted.current) return;\n greeted.current = true;\n const timers: ReturnType<typeof setTimeout>[] = [];\n order.forEach((index, n) => {\n timers.push(setTimeout(() => setPoked((p) => ({ ...p, [index]: true })), n * GREET_STEP_MS));\n timers.push(setTimeout(() => setPoked((p) => ({ ...p, [index]: false })), n * GREET_STEP_MS + POKE_MS));\n });\n return () => timers.forEach(clearTimeout);\n }, [running, greet, order]);\n\n // The bird the page points at looks up and jumps.\n React.useEffect(() => {\n const index = active ? birds.findIndex((b) => b.bird === active) : -1;\n if (!running || index < 0) return;\n const start = setTimeout(() => {\n look(index, \"up\");\n setPoked((p) => ({ ...p, [index]: true }));\n }, 0);\n const t = setTimeout(() => setPoked((p) => ({ ...p, [index]: false })), POKE_MS);\n return () => {\n clearTimeout(start);\n clearTimeout(t);\n setPoked((p) => ({ ...p, [index]: false }));\n rest(index);\n };\n }, [active, running, birds]);\n\n // A bird looks up when you come near, and jumps when you tap it.\n const hover = (index: number, event: React.PointerEvent) => {\n if (!running || !react || event.pointerType !== \"mouse\") return;\n look(index, \"up\");\n };\n const leave = (index: number) => {\n if (!react) return;\n rest(index);\n };\n const tap = (index: number) => {\n if (!running || !react) return;\n look(index, \"up\");\n setPoked((p) => ({ ...p, [index]: true }));\n setTimeout(() => {\n setPoked((p) => ({ ...p, [index]: false }));\n rest(index);\n }, LOOK_BACK_MS);\n };\n\n return (\n <div\n ref={stage}\n aria-hidden\n data-flock=\"\"\n data-running={running ? \"\" : undefined}\n className={cn(\"relative w-full\", className)}\n style={{ aspectRatio: String(ratio), containerType: \"inline-size\", ...style }}\n {...props}\n >\n {birds.map((b, i) => (\n <div\n key={`${b.bird}-${i}`}\n ref={(el) => {\n bodies.current[i] = el;\n }}\n data-flock-bird={b.bird}\n className=\"absolute touch-manipulation\"\n style={{ left: `${b.x - b.size / 2}%`, width: `${b.size}%`, top: `calc(${b.y}% - ${b.size * 0.9}cqw)`, aspectRatio: \"1\", pointerEvents: react ? \"auto\" : \"none\" }}\n onPointerEnter={(event) => hover(i, event)}\n onPointerLeave={() => leave(i)}\n onPointerDown={() => tap(i)}\n >\n <Mascot\n bird={b.bird}\n tone={tone}\n life\n look={looks[i]}\n flying={flying?.index === i}\n bank={flying?.index === i ? flying.bank : 0}\n poked={poked[i]}\n size={120}\n style={{ width: \"100%\", height: \"100%\", display: \"block\", overflow: \"visible\" }}\n />\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krizaka/ui",
3
- "version": "3.40.0",
3
+ "version": "3.41.0",
4
4
  "description": "The Krizaka front-end platform's components: the primitives (button, card, dialog, toast, menu, field, tabs, chip, switch, slider, command palette, theme, countdown…) on the semantic --kz-* tokens, the animated marks (Krizaka, Orazaka, Orochia, Yasakia, Yororis) and the motion signature — web and /native.",
5
5
  "keywords": [
6
6
  "krizaka",
@@ -745,7 +745,7 @@
745
745
  ],
746
746
  "peerDependencies": {
747
747
  "@krizaka/query": ">=0.2.1",
748
- "@krizaka/tailwind": ">=3.40.0",
748
+ "@krizaka/tailwind": ">=3.41.0",
749
749
  "@maplibre/maplibre-react-native": ">=11",
750
750
  "@shopify/flash-list": ">=2",
751
751
  "expo-camera": ">=16",
@@ -805,8 +805,8 @@
805
805
  "typescript": "^5.9.0",
806
806
  "vitest": "^4.1.11",
807
807
  "zod": "^4.6.5",
808
- "@krizaka/query": "0.2.1",
809
- "@krizaka/config": "0.4.1"
808
+ "@krizaka/config": "0.4.1",
809
+ "@krizaka/query": "0.2.1"
810
810
  },
811
811
  "engines": {
812
812
  "node": ">=22"
@@ -2550,7 +2550,7 @@
2550
2550
  "tailwind-variants": "^3.3.1",
2551
2551
  "@krizaka/intl": "^0.2.1",
2552
2552
  "@krizaka/pacer": "^0.1.0",
2553
- "@krizaka/tokens": "^3.40.0"
2553
+ "@krizaka/tokens": "^3.41.0"
2554
2554
  },
2555
2555
  "scripts": {
2556
2556
  "build": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true});for(const f of fs.readdirSync('registry/examples',{recursive:true}))if(/\\.(js|d\\.ts)$/.test(f))fs.rmSync('registry/examples/'+f)\" && tsup && node -e \"require('node:fs').copyFileSync('src/motion.css','dist/motion.css');require('node:fs').copyFileSync('src/blocks.css','dist/blocks.css');require('node:fs').copyFileSync('src/story.css','dist/story.css')\" && node scripts/build-registry.mjs",
@@ -127,7 +127,7 @@
127
127
  "description": "Discuss, propose, report: icon buttons with their words in a tooltip.",
128
128
  "path": "examples/action-bar/icons.tsx",
129
129
  "module": "@krizaka/ui/registry/examples/action-bar/icons",
130
- "code": "import { ActionBar } from \"@krizaka/ui/action-bar\";\n\nconst glyph = (d: string) => (\n <svg viewBox=\"0 0 24 24\" width=\"17\" height=\"17\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d={d} />\n </svg>\n);\nconst repo = \"https://github.com/krizaka/krizaka-build\";\n\n// `icons`: where room is short (the foot of a card) — the words are the accessible name and a tooltip on hover and focus.\nexport default function ActionBarIcons() {\n return (\n <ActionBar\n variant=\"icons\"\n label=\"Talk about Krizaka Java\"\n actions={[\n { href: `${repo}/discussions`, label: \"Discuss\", icon: glyph(\"M4 5h16v11H9l-5 4V5Z\") },\n { href: `${repo}/issues/new?template=idea.yml`, label: \"Propose\", icon: glyph(\"M12 3v4M5 12H3m18 0h-2M8 17h8m-6 4h4M12 7a5 5 0 0 0-3 9h6a5 5 0 0 0-3-9Z\") },\n { href: `${repo}/issues/new?template=bug.yml`, label: \"Report a problem\", icon: glyph(\"M12 4 2.5 20h19L12 4Zm0 6v4m0 3v.1\") },\n ]}\n />\n );\n}\n"
130
+ "code": "import { ActionBar } from \"@krizaka/ui/action-bar\";\n\nconst glyph = (d: string) => (\n <svg viewBox=\"0 0 24 24\" width=\"17\" height=\"17\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d={d} />\n </svg>\n);\nconst repo = \"https://github.com/krizaka/krizaka-build\";\n\n// `icons`: where room is short (the foot of a card) — the words are the accessible name and a tooltip on hover and focus.\nexport default function ActionBarIcons() {\n return (\n <ActionBar\n variant=\"icons\"\n label=\"Talk about Krizaka Java\"\n actions={[\n { href: `https://github.com/krizaka/krizaka-ui/discussions`, label: \"Discuss\", icon: glyph(\"M4 5h16v11H9l-5 4V5Z\") },\n { href: `${repo}/issues/new?template=idea.yml`, label: \"Propose\", icon: glyph(\"M12 3v4M5 12H3m18 0h-2M8 17h8m-6 4h4M12 7a5 5 0 0 0-3 9h6a5 5 0 0 0-3-9Z\") },\n { href: `${repo}/issues/new?template=bug.yml`, label: \"Report a problem\", icon: glyph(\"M12 4 2.5 20h19L12 4Zm0 6v4m0 3v.1\") },\n ]}\n />\n );\n}\n"
131
131
  }
132
132
  ]
133
133
  },
@@ -12,7 +12,7 @@ function ActionBarIcons() {
12
12
  variant: "icons",
13
13
  label: "Talk about Krizaka Java",
14
14
  actions: [
15
- { href: `${repo}/discussions`, label: "Discuss", icon: glyph("M4 5h16v11H9l-5 4V5Z") },
15
+ { href: `https://github.com/krizaka/krizaka-ui/discussions`, label: "Discuss", icon: glyph("M4 5h16v11H9l-5 4V5Z") },
16
16
  { href: `${repo}/issues/new?template=idea.yml`, label: "Propose", icon: glyph("M12 3v4M5 12H3m18 0h-2M8 17h8m-6 4h4M12 7a5 5 0 0 0-3 9h6a5 5 0 0 0-3-9Z") },
17
17
  { href: `${repo}/issues/new?template=bug.yml`, label: "Report a problem", icon: glyph("M12 4 2.5 20h19L12 4Zm0 6v4m0 3v.1") }
18
18
  ]
@@ -14,7 +14,7 @@ export default function ActionBarIcons() {
14
14
  variant="icons"
15
15
  label="Talk about Krizaka Java"
16
16
  actions={[
17
- { href: `${repo}/discussions`, label: "Discuss", icon: glyph("M4 5h16v11H9l-5 4V5Z") },
17
+ { href: `https://github.com/krizaka/krizaka-ui/discussions`, label: "Discuss", icon: glyph("M4 5h16v11H9l-5 4V5Z") },
18
18
  { href: `${repo}/issues/new?template=idea.yml`, label: "Propose", icon: glyph("M12 3v4M5 12H3m18 0h-2M8 17h8m-6 4h4M12 7a5 5 0 0 0-3 9h6a5 5 0 0 0-3-9Z") },
19
19
  { href: `${repo}/issues/new?template=bug.yml`, label: "Report a problem", icon: glyph("M12 4 2.5 20h19L12 4Zm0 6v4m0 3v.1") },
20
20
  ]}
@@ -4,7 +4,7 @@
4
4
  import { Progress } from "@krizaka/ui/progress";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  function ProgressBarSizes() {
7
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
7
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-64 max-w-full flex-col gap-4", children: [
8
8
  /* @__PURE__ */ jsx(Progress, { label: "Small", size: "sm", value: 30 }),
9
9
  /* @__PURE__ */ jsx(Progress, { label: "Medium", size: "md", value: 55 }),
10
10
  /* @__PURE__ */ jsx(Progress, { label: "Large", size: "lg", value: 80 })
@@ -2,7 +2,7 @@ import { Progress } from "@krizaka/ui/progress";
2
2
 
3
3
  export default function ProgressBarSizes() {
4
4
  return (
5
- <div className="flex flex-col gap-4">
5
+ <div className="flex w-64 max-w-full flex-col gap-4">
6
6
  <Progress label="Small" size="sm" value={30} />
7
7
  <Progress label="Medium" size="md" value={55} />
8
8
  <Progress label="Large" size="lg" value={80} />
@@ -43,6 +43,7 @@
43
43
  "One flock per page, under the words and never behind them: the birds are the scene, not the message.",
44
44
  "Give the stage the ratio of its backdrop (`ratio`) and the birds' places in percent: they keep their positions at any width.",
45
45
  "Keep each bird to its job: the falcon watches, the owl reads, the duck builds, the flamingo answers, the pigeon delivers.",
46
+ "Make it the page's own: `active` is the bird of the product the reader is on (it looks up and jumps), `greet` has every bird jump once as the flock comes into view, `tempo` makes the moments more frequent.",
46
47
  "Turn a moment off with `glance={false}`, `courier={false}` or `react={false}` on a page that already moves."
47
48
  ],
48
49
  "accessibility": {
@@ -74,6 +75,13 @@
74
75
  "description": "The birds on the stage.",
75
76
  "required": true
76
77
  },
78
+ {
79
+ "name": "active",
80
+ "type": "\"falcon\" | \"owl\" | \"duck\" | \"flamingo\" | \"pigeon\" | \"lovebird\" | \"crane\" | \"magpie\" | \"beaver\" | null",
81
+ "default": "null",
82
+ "description": "A bird the page points at (a product the reader is on): it looks up and jumps once each time it changes.",
83
+ "required": false
84
+ },
77
85
  {
78
86
  "name": "courier",
79
87
  "type": "boolean",
@@ -88,6 +96,13 @@
88
96
  "description": "Two neighbours look at each other now and then. Default `true`.",
89
97
  "required": false
90
98
  },
99
+ {
100
+ "name": "greet",
101
+ "type": "boolean",
102
+ "default": "false",
103
+ "description": "The birds greet the reader once as the flock first comes into view: each jumps in turn, left to right.",
104
+ "required": false
105
+ },
91
106
  {
92
107
  "name": "random",
93
108
  "type": "(() => number)",
@@ -109,6 +124,13 @@
109
124
  "description": "A bird looks up when the pointer comes near, and jumps a little when tapped. Default `true`.",
110
125
  "required": false
111
126
  },
127
+ {
128
+ "name": "tempo",
129
+ "type": "number",
130
+ "default": "1",
131
+ "description": "How lively the moments are: 1 is calm (default), 2 doubles how often neighbours glance and the pigeon delivers.",
132
+ "required": false
133
+ },
112
134
  {
113
135
  "name": "tone",
114
136
  "type": "\"brand\" | \"own\"",
@@ -142,7 +164,7 @@
142
164
  "files": [
143
165
  {
144
166
  "path": "flock/flock.tsx",
145
- "content": "\"use client\";\n\n// The flock, alive: birds standing on a stage, each at ease in character (Mascot `life`), and the moments between\n// them — two birds glance at each other, the pigeon carries its parcel across, a bird looks up when you come near or tap\n// it. Transform and opacity only: CSS for each bird's own life, a timer for the moments (no frame loop), and nothing at\n// all when the flock is off screen, the tab is hidden or the person asked for less motion.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport type { MascotBird, MascotLook } from \"../mascots\";\nimport { Mascot } from \"../mascots\";\n\nexport interface FlockBird {\n /** Which bird. */\n bird: MascotBird;\n /** Where its feet are, across the stage: 0 to 100 (% of the stage's width). */\n x: number;\n /** Where its feet are, down the stage: 0 to 100 (% of the stage's height). */\n y: number;\n /** How wide it is: % of the stage's width. */\n size: number;\n}\n\nexport interface FlockMoments {\n /** Two neighbours look at each other now and then. Default `true`. */\n glance?: boolean;\n /** The pigeon, when the flock has one, carries its parcel across to another bird and comes back. Default `true`. */\n courier?: boolean;\n /** A bird looks up when the pointer comes near, and jumps a little when tapped. Default `true`. */\n react?: boolean;\n}\n\nexport type FlockProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n FlockMoments & {\n /** The birds on the stage. */\n birds: readonly FlockBird[];\n /** The stage's shape, width over height (default 16 / 9). It keeps its ratio at any width, so the birds keep their places. */\n ratio?: number;\n /** The birds' colours: the host's accent (`brand`, default) or the Krizaka story's (`own`). */\n tone?: \"brand\" | \"own\";\n /** The source of chance (default `Math.random`): give it a fixed one in a test. */\n random?: () => number;\n };\n\n// @fixed: the rhythm of the moments — how long a glance lasts, how often one happens, how long a delivery takes. A\n// choreography's pace, not a business parameter.\nconst GLANCE_HOLD_MS = [1500, 2400] as const;\nconst GLANCE_EVERY_MS = [4200, 9000] as const;\nconst COURIER_FIRST_MS = 9000;\nconst COURIER_EVERY_MS = [26000, 38000] as const;\nconst FLIGHT_MS = 2600;\nconst HAND_OVER_MS = 1300;\nconst LOOK_BACK_MS = 1600;\n\nconst between = (random: () => number, [lo, hi]: readonly [number, number]) => lo + random() * (hi - lo);\n\n/** `true` while the page may move: no reduced-motion request, the tab visible. */\nfunction useMayMove(): boolean {\n const [may, setMay] = React.useState(false);\n React.useEffect(() => {\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const update = () => setMay(!query.matches && document.visibilityState !== \"hidden\");\n update();\n query.addEventListener(\"change\", update);\n document.addEventListener(\"visibilitychange\", update);\n return () => {\n query.removeEventListener(\"change\", update);\n document.removeEventListener(\"visibilitychange\", update);\n };\n }, []);\n return may;\n}\n\n/** `true` while the element is on screen. */\nfunction useOnScreen(ref: React.RefObject<Element | null>): boolean {\n const [on, setOn] = React.useState(false);\n React.useEffect(() => {\n const el = ref.current;\n if (!el || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => setOn(Boolean(entry?.isIntersecting)), { threshold: 0.1 });\n observer.observe(el);\n return () => observer.disconnect();\n }, [ref]);\n return on;\n}\n\n/**\n * The flock on its stage, alive. Decorative (`aria-hidden`): put the words beside it. Each bird idles in character; every\n * few seconds two neighbours glance at each other; every half minute the pigeon carries its parcel to another bird and\n * returns; a bird looks up when you come near. All of it pauses off screen and in a hidden tab, and the flock is still\n * under `prefers-reduced-motion`.\n */\nexport function Flock({ birds, ratio = 16 / 9, tone = \"brand\", glance = true, courier = true, react = true, random = Math.random, className, style, ...props }: FlockProps) {\n const stage = React.useRef<HTMLDivElement>(null);\n const bodies = React.useRef<(HTMLDivElement | null)[]>([]);\n const may = useMayMove();\n const onScreen = useOnScreen(stage);\n const running = may && onScreen;\n const [looks, setLooks] = React.useState<Record<number, MascotLook>>({});\n const [flying, setFlying] = React.useState<{ index: number; bank: number } | null>(null);\n const [poked, setPoked] = React.useState<Record<number, boolean>>({});\n\n // Left to right: a bird's neighbours are the birds beside it on the stage.\n const order = React.useMemo(() => birds.map((_, i) => i).sort((a, b) => birds[a]!.x - birds[b]!.x), [birds]);\n const look = (index: number, to: MascotLook) => setLooks((l) => (l[index] === to ? l : { ...l, [index]: to }));\n const rest = (...indexes: number[]) => setLooks((l) => Object.fromEntries(Object.entries(l).filter(([k]) => !indexes.includes(Number(k)))));\n\n // Glances: two neighbours turn towards each other, hold, and look away.\n React.useEffect(() => {\n if (!running || !glance || order.length < 2) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let back: ReturnType<typeof setTimeout> | undefined;\n const next = () => {\n timer = setTimeout(() => {\n const at = Math.floor(random() * (order.length - 1));\n const [a, b] = [order[at]!, order[at + 1]!];\n look(a, \"right\");\n look(b, \"left\");\n back = setTimeout(() => {\n rest(a, b);\n next();\n }, between(random, GLANCE_HOLD_MS));\n }, between(random, GLANCE_EVERY_MS));\n };\n next();\n return () => {\n clearTimeout(timer);\n clearTimeout(back);\n };\n }, [running, glance, order, random]);\n\n // The delivery: the pigeon takes its parcel across to the farthest bird, hands it over, and flies back.\n React.useEffect(() => {\n const pigeon = birds.findIndex((b) => b.bird === \"pigeon\");\n if (!running || !courier || pigeon < 0 || birds.length < 2) return;\n let alive = true;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let animation: Animation | undefined;\n const wait = (ms: number) => new Promise<void>((resolve) => (timer = setTimeout(resolve, ms)));\n const trip = async () => {\n const el = bodies.current[pigeon];\n const box = stage.current?.getBoundingClientRect();\n if (!el || !box || typeof el.animate !== \"function\") return;\n // The farthest bird from the pigeon, so the parcel crosses the whole stage.\n const from = birds[pigeon]!;\n const target = birds.reduce((far, b, i) => (i !== pigeon && Math.abs(b.x - from.x) > Math.abs(birds[far]!.x - from.x) ? i : far), pigeon === 0 ? 1 : 0);\n const to = birds[target]!;\n const side = to.x > from.x ? 1 : -1;\n // It lands beside the receiver, not on it.\n const dx = ((to.x - from.x) / 100) * box.width - side * (to.size / 100) * box.width * 0.55;\n const lift = (from.size / 100) * box.width * 0.35;\n const fly = async (fromX: number, toX: number) => {\n setFlying({ index: pigeon, bank: Math.sign(toX - fromX) });\n animation = el.animate(\n [\n { transform: `translate(${fromX}px, 0)`, easing: \"ease-out\" },\n { transform: `translate(${(fromX + toX) / 2}px, ${-lift}px)`, easing: \"ease-in\", offset: 0.5 },\n { transform: `translate(${toX}px, 0)` },\n ],\n { duration: FLIGHT_MS, fill: \"forwards\" },\n );\n await animation.finished.catch(() => undefined);\n setFlying(null);\n };\n look(target, side > 0 ? \"left\" : \"right\");\n await fly(0, dx);\n if (!alive) return;\n // The hand-over: the receiver looks at the pigeon, the pigeon hops on the doorstep.\n setPoked((p) => ({ ...p, [pigeon]: true }));\n await wait(HAND_OVER_MS);\n if (!alive) return;\n setPoked((p) => ({ ...p, [pigeon]: false }));\n look(target, \"up\");\n await fly(dx, 0);\n animation?.cancel();\n rest(target);\n };\n const schedule = (ms: number) => {\n timer = setTimeout(async () => {\n await trip();\n if (alive) schedule(between(random, COURIER_EVERY_MS));\n }, ms);\n };\n schedule(COURIER_FIRST_MS);\n return () => {\n alive = false;\n clearTimeout(timer);\n animation?.cancel();\n setFlying(null);\n };\n }, [running, courier, birds, random]);\n\n // A bird looks up when you come near, and jumps when you tap it.\n const hover = (index: number, event: React.PointerEvent) => {\n if (!running || !react || event.pointerType !== \"mouse\") return;\n look(index, \"up\");\n };\n const leave = (index: number) => {\n if (!react) return;\n rest(index);\n };\n const tap = (index: number) => {\n if (!running || !react) return;\n look(index, \"up\");\n setPoked((p) => ({ ...p, [index]: true }));\n setTimeout(() => {\n setPoked((p) => ({ ...p, [index]: false }));\n rest(index);\n }, LOOK_BACK_MS);\n };\n\n return (\n <div\n ref={stage}\n aria-hidden\n data-flock=\"\"\n data-running={running ? \"\" : undefined}\n className={cn(\"relative w-full\", className)}\n style={{ aspectRatio: String(ratio), containerType: \"inline-size\", ...style }}\n {...props}\n >\n {birds.map((b, i) => (\n <div\n key={`${b.bird}-${i}`}\n ref={(el) => {\n bodies.current[i] = el;\n }}\n data-flock-bird={b.bird}\n className=\"absolute touch-manipulation\"\n style={{ left: `${b.x - b.size / 2}%`, width: `${b.size}%`, top: `calc(${b.y}% - ${b.size * 0.9}cqw)`, aspectRatio: \"1\", pointerEvents: react ? \"auto\" : \"none\" }}\n onPointerEnter={(event) => hover(i, event)}\n onPointerLeave={() => leave(i)}\n onPointerDown={() => tap(i)}\n >\n <Mascot\n bird={b.bird}\n tone={tone}\n life\n look={looks[i]}\n flying={flying?.index === i}\n bank={flying?.index === i ? flying.bank : 0}\n poked={poked[i]}\n size={120}\n style={{ width: \"100%\", height: \"100%\", display: \"block\", overflow: \"visible\" }}\n />\n </div>\n ))}\n </div>\n );\n}\n"
167
+ "content": "\"use client\";\n\n// The flock, alive: birds standing on a stage, each at ease in character (Mascot `life`), and the moments between\n// them — two birds glance at each other, the pigeon carries its parcel across, a bird looks up when you come near or tap\n// it. Transform and opacity only: CSS for each bird's own life, a timer for the moments (no frame loop), and nothing at\n// all when the flock is off screen, the tab is hidden or the person asked for less motion.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport type { MascotBird, MascotLook } from \"../mascots\";\nimport { Mascot } from \"../mascots\";\n\nexport interface FlockBird {\n /** Which bird. */\n bird: MascotBird;\n /** Where its feet are, across the stage: 0 to 100 (% of the stage's width). */\n x: number;\n /** Where its feet are, down the stage: 0 to 100 (% of the stage's height). */\n y: number;\n /** How wide it is: % of the stage's width. */\n size: number;\n}\n\nexport interface FlockMoments {\n /** Two neighbours look at each other now and then. Default `true`. */\n glance?: boolean;\n /** The pigeon, when the flock has one, carries its parcel across to another bird and comes back. Default `true`. */\n courier?: boolean;\n /** A bird looks up when the pointer comes near, and jumps a little when tapped. Default `true`. */\n react?: boolean;\n}\n\nexport type FlockProps = Omit<React.ComponentProps<\"div\">, \"children\"> &\n FlockMoments & {\n /** The birds on the stage. */\n birds: readonly FlockBird[];\n /** The stage's shape, width over height (default 16 / 9). It keeps its ratio at any width, so the birds keep their places. */\n ratio?: number;\n /** The birds' colours: the host's accent (`brand`, default) or the Krizaka story's (`own`). */\n tone?: \"brand\" | \"own\";\n /** The source of chance (default `Math.random`): give it a fixed one in a test. */\n random?: () => number;\n /** How lively the moments are: 1 is calm (default), 2 doubles how often neighbours glance and the pigeon delivers. */\n tempo?: number;\n /** A bird the page points at (a product the reader is on): it looks up and jumps once each time it changes. */\n active?: MascotBird | null;\n /** The birds greet the reader once as the flock first comes into view: each jumps in turn, left to right. */\n greet?: boolean;\n };\n\n// @fixed: the rhythm of the moments — how long a glance lasts, how often one happens, how long a delivery takes. A\n// choreography's pace, not a business parameter.\nconst GLANCE_HOLD_MS = [1500, 2400] as const;\nconst GLANCE_EVERY_MS = [4200, 9000] as const;\nconst COURIER_FIRST_MS = 9000;\nconst COURIER_EVERY_MS = [26000, 38000] as const;\nconst FLIGHT_MS = 2600;\nconst HAND_OVER_MS = 1300;\nconst LOOK_BACK_MS = 1600;\n\nconst between = (random: () => number, [lo, hi]: readonly [number, number], tempo = 1) => (lo + random() * (hi - lo)) / tempo;\nconst GREET_STEP_MS = 110;\nconst POKE_MS = 700;\n\n/** `true` while the page may move: no reduced-motion request, the tab visible. */\nfunction useMayMove(): boolean {\n const [may, setMay] = React.useState(false);\n React.useEffect(() => {\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const update = () => setMay(!query.matches && document.visibilityState !== \"hidden\");\n update();\n query.addEventListener(\"change\", update);\n document.addEventListener(\"visibilitychange\", update);\n return () => {\n query.removeEventListener(\"change\", update);\n document.removeEventListener(\"visibilitychange\", update);\n };\n }, []);\n return may;\n}\n\n/** `true` while the element is on screen. */\nfunction useOnScreen(ref: React.RefObject<Element | null>): boolean {\n const [on, setOn] = React.useState(false);\n React.useEffect(() => {\n const el = ref.current;\n if (!el || typeof IntersectionObserver === \"undefined\") return;\n const observer = new IntersectionObserver(([entry]) => setOn(Boolean(entry?.isIntersecting)), { threshold: 0.1 });\n observer.observe(el);\n return () => observer.disconnect();\n }, [ref]);\n return on;\n}\n\n/**\n * The flock on its stage, alive. Decorative (`aria-hidden`): put the words beside it. Each bird idles in character; every\n * few seconds two neighbours glance at each other; every half minute the pigeon carries its parcel to another bird and\n * returns; a bird looks up when you come near. All of it pauses off screen and in a hidden tab, and the flock is still\n * under `prefers-reduced-motion`.\n */\nexport function Flock({ birds, ratio = 16 / 9, tone = \"brand\", glance = true, courier = true, react = true, random = Math.random, tempo = 1, active = null, greet = false, className, style, ...props }: FlockProps) {\n const stage = React.useRef<HTMLDivElement>(null);\n const bodies = React.useRef<(HTMLDivElement | null)[]>([]);\n const may = useMayMove();\n const onScreen = useOnScreen(stage);\n const running = may && onScreen;\n const [looks, setLooks] = React.useState<Record<number, MascotLook>>({});\n const [flying, setFlying] = React.useState<{ index: number; bank: number } | null>(null);\n const [poked, setPoked] = React.useState<Record<number, boolean>>({});\n\n // Left to right: a bird's neighbours are the birds beside it on the stage.\n const order = React.useMemo(() => birds.map((_, i) => i).sort((a, b) => birds[a]!.x - birds[b]!.x), [birds]);\n const look = (index: number, to: MascotLook) => setLooks((l) => (l[index] === to ? l : { ...l, [index]: to }));\n const rest = (...indexes: number[]) => setLooks((l) => Object.fromEntries(Object.entries(l).filter(([k]) => !indexes.includes(Number(k)))));\n\n // Glances: two neighbours turn towards each other, hold, and look away.\n React.useEffect(() => {\n if (!running || !glance || order.length < 2) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let back: ReturnType<typeof setTimeout> | undefined;\n const next = () => {\n timer = setTimeout(() => {\n const at = Math.floor(random() * (order.length - 1));\n const [a, b] = [order[at]!, order[at + 1]!];\n look(a, \"right\");\n look(b, \"left\");\n back = setTimeout(() => {\n rest(a, b);\n next();\n }, between(random, GLANCE_HOLD_MS));\n }, between(random, GLANCE_EVERY_MS, tempo));\n };\n next();\n return () => {\n clearTimeout(timer);\n clearTimeout(back);\n };\n }, [running, glance, order, random, tempo]);\n\n // The delivery: the pigeon takes its parcel across to the farthest bird, hands it over, and flies back.\n React.useEffect(() => {\n const pigeon = birds.findIndex((b) => b.bird === \"pigeon\");\n if (!running || !courier || pigeon < 0 || birds.length < 2) return;\n let alive = true;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let animation: Animation | undefined;\n const wait = (ms: number) => new Promise<void>((resolve) => (timer = setTimeout(resolve, ms)));\n const trip = async () => {\n const el = bodies.current[pigeon];\n const box = stage.current?.getBoundingClientRect();\n if (!el || !box || typeof el.animate !== \"function\") return;\n // The farthest bird from the pigeon, so the parcel crosses the whole stage.\n const from = birds[pigeon]!;\n const target = birds.reduce((far, b, i) => (i !== pigeon && Math.abs(b.x - from.x) > Math.abs(birds[far]!.x - from.x) ? i : far), pigeon === 0 ? 1 : 0);\n const to = birds[target]!;\n const side = to.x > from.x ? 1 : -1;\n // It lands beside the receiver, not on it.\n const dx = ((to.x - from.x) / 100) * box.width - side * (to.size / 100) * box.width * 0.55;\n const lift = (from.size / 100) * box.width * 0.35;\n const fly = async (fromX: number, toX: number) => {\n setFlying({ index: pigeon, bank: Math.sign(toX - fromX) });\n animation = el.animate(\n [\n { transform: `translate(${fromX}px, 0)`, easing: \"ease-out\" },\n { transform: `translate(${(fromX + toX) / 2}px, ${-lift}px)`, easing: \"ease-in\", offset: 0.5 },\n { transform: `translate(${toX}px, 0)` },\n ],\n { duration: FLIGHT_MS, fill: \"forwards\" },\n );\n await animation.finished.catch(() => undefined);\n setFlying(null);\n };\n look(target, side > 0 ? \"left\" : \"right\");\n await fly(0, dx);\n if (!alive) return;\n // The hand-over: the receiver looks at the pigeon, the pigeon hops on the doorstep.\n setPoked((p) => ({ ...p, [pigeon]: true }));\n await wait(HAND_OVER_MS);\n if (!alive) return;\n setPoked((p) => ({ ...p, [pigeon]: false }));\n look(target, \"up\");\n await fly(dx, 0);\n animation?.cancel();\n rest(target);\n };\n const schedule = (ms: number) => {\n timer = setTimeout(async () => {\n await trip();\n if (alive) schedule(between(random, COURIER_EVERY_MS, tempo));\n }, ms);\n };\n schedule(COURIER_FIRST_MS / tempo);\n return () => {\n alive = false;\n clearTimeout(timer);\n animation?.cancel();\n setFlying(null);\n };\n }, [running, courier, birds, random, tempo]);\n\n // The greeting: the first time the flock is on screen, each bird jumps in turn.\n const greeted = React.useRef(false);\n React.useEffect(() => {\n if (!running || !greet || greeted.current) return;\n greeted.current = true;\n const timers: ReturnType<typeof setTimeout>[] = [];\n order.forEach((index, n) => {\n timers.push(setTimeout(() => setPoked((p) => ({ ...p, [index]: true })), n * GREET_STEP_MS));\n timers.push(setTimeout(() => setPoked((p) => ({ ...p, [index]: false })), n * GREET_STEP_MS + POKE_MS));\n });\n return () => timers.forEach(clearTimeout);\n }, [running, greet, order]);\n\n // The bird the page points at looks up and jumps.\n React.useEffect(() => {\n const index = active ? birds.findIndex((b) => b.bird === active) : -1;\n if (!running || index < 0) return;\n const start = setTimeout(() => {\n look(index, \"up\");\n setPoked((p) => ({ ...p, [index]: true }));\n }, 0);\n const t = setTimeout(() => setPoked((p) => ({ ...p, [index]: false })), POKE_MS);\n return () => {\n clearTimeout(start);\n clearTimeout(t);\n setPoked((p) => ({ ...p, [index]: false }));\n rest(index);\n };\n }, [active, running, birds]);\n\n // A bird looks up when you come near, and jumps when you tap it.\n const hover = (index: number, event: React.PointerEvent) => {\n if (!running || !react || event.pointerType !== \"mouse\") return;\n look(index, \"up\");\n };\n const leave = (index: number) => {\n if (!react) return;\n rest(index);\n };\n const tap = (index: number) => {\n if (!running || !react) return;\n look(index, \"up\");\n setPoked((p) => ({ ...p, [index]: true }));\n setTimeout(() => {\n setPoked((p) => ({ ...p, [index]: false }));\n rest(index);\n }, LOOK_BACK_MS);\n };\n\n return (\n <div\n ref={stage}\n aria-hidden\n data-flock=\"\"\n data-running={running ? \"\" : undefined}\n className={cn(\"relative w-full\", className)}\n style={{ aspectRatio: String(ratio), containerType: \"inline-size\", ...style }}\n {...props}\n >\n {birds.map((b, i) => (\n <div\n key={`${b.bird}-${i}`}\n ref={(el) => {\n bodies.current[i] = el;\n }}\n data-flock-bird={b.bird}\n className=\"absolute touch-manipulation\"\n style={{ left: `${b.x - b.size / 2}%`, width: `${b.size}%`, top: `calc(${b.y}% - ${b.size * 0.9}cqw)`, aspectRatio: \"1\", pointerEvents: react ? \"auto\" : \"none\" }}\n onPointerEnter={(event) => hover(i, event)}\n onPointerLeave={() => leave(i)}\n onPointerDown={() => tap(i)}\n >\n <Mascot\n bird={b.bird}\n tone={tone}\n life\n look={looks[i]}\n flying={flying?.index === i}\n bank={flying?.index === i ? flying.bank : 0}\n poked={poked[i]}\n size={120}\n style={{ width: \"100%\", height: \"100%\", display: \"block\", overflow: \"visible\" }}\n />\n </div>\n ))}\n </div>\n );\n}\n"
146
168
  },
147
169
  {
148
170
  "path": "flock/index.ts",
@@ -150,7 +172,7 @@
150
172
  },
151
173
  {
152
174
  "path": "flock/meta.ts",
153
- "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Flock\",\n summary:\n \"The Krizaka birds standing on a stage, alive: each at ease in character, two neighbours glancing at each other, the pigeon carrying its parcel across, a bird looking up when you come near or tap it.\",\n status: \"beta\",\n category: \"blocks\",\n platforms: \"web\",\n parity: {\n native: { status: \"n/a\", reason: \"A decorative stage for a public page's first screen; an app screen speaks with MascotState.\", use: \"mascot-state\" },\n desktop: \"web\",\n },\n whenToUse: [\n \"On a company's home, where the flock is the scene: five birds on a ridge, under the words.\",\n \"On an about or story page, where the birds are the subject and a still drawing would feel dead.\",\n ],\n whenNotToUse: [\n { when: \"A bird that answers a state (a wait, an error, an empty list).\", use: \"mascot-state\" },\n { when: \"One bird at ease inside a card or beside a rule.\", use: \"mascots\" },\n { when: \"The flock as a still plate with its promises.\", use: \"bird-plate\" },\n ],\n bestPractices: [\n \"One flock per page, under the words and never behind them: the birds are the scene, not the message.\",\n \"Give the stage the ratio of its backdrop (`ratio`) and the birds' places in percent: they keep their positions at any width.\",\n \"Keep each bird to its job: the falcon watches, the owl reads, the duck builds, the flamingo answers, the pigeon delivers.\",\n \"Turn a moment off with `glance={false}`, `courier={false}` or `react={false}` on a page that already moves.\",\n ],\n accessibility: {\n keyboard: [],\n notes: [\n \"Decorative (`aria-hidden`): it never carries information; put the words beside it.\",\n \"Under `prefers-reduced-motion` the birds are still: no idle motion, no glance, no delivery, no reaction.\",\n \"The moments pause while the flock is off screen and while the tab is hidden; there is no frame loop.\",\n ],\n },\n related: [\"mascots\", \"mascot-state\", \"bird-plate\", \"landscape\"],\n web: {\n imports: [\"Flock\"],\n examples: [\n { name: \"ridge\", title: \"The flock on its ridge\", description: \"Five birds across a stage, each at ease; neighbours glance, the pigeon delivers.\" },\n { name: \"pair\", title: \"Two birds\", description: \"The owl and the duck: they look at each other now and then.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
175
+ "content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Flock\",\n summary:\n \"The Krizaka birds standing on a stage, alive: each at ease in character, two neighbours glancing at each other, the pigeon carrying its parcel across, a bird looking up when you come near or tap it.\",\n status: \"beta\",\n category: \"blocks\",\n platforms: \"web\",\n parity: {\n native: { status: \"n/a\", reason: \"A decorative stage for a public page's first screen; an app screen speaks with MascotState.\", use: \"mascot-state\" },\n desktop: \"web\",\n },\n whenToUse: [\n \"On a company's home, where the flock is the scene: five birds on a ridge, under the words.\",\n \"On an about or story page, where the birds are the subject and a still drawing would feel dead.\",\n ],\n whenNotToUse: [\n { when: \"A bird that answers a state (a wait, an error, an empty list).\", use: \"mascot-state\" },\n { when: \"One bird at ease inside a card or beside a rule.\", use: \"mascots\" },\n { when: \"The flock as a still plate with its promises.\", use: \"bird-plate\" },\n ],\n bestPractices: [\n \"One flock per page, under the words and never behind them: the birds are the scene, not the message.\",\n \"Give the stage the ratio of its backdrop (`ratio`) and the birds' places in percent: they keep their positions at any width.\",\n \"Keep each bird to its job: the falcon watches, the owl reads, the duck builds, the flamingo answers, the pigeon delivers.\",\n \"Make it the page's own: `active` is the bird of the product the reader is on (it looks up and jumps), `greet` has every bird jump once as the flock comes into view, `tempo` makes the moments more frequent.\",\n \"Turn a moment off with `glance={false}`, `courier={false}` or `react={false}` on a page that already moves.\",\n ],\n accessibility: {\n keyboard: [],\n notes: [\n \"Decorative (`aria-hidden`): it never carries information; put the words beside it.\",\n \"Under `prefers-reduced-motion` the birds are still: no idle motion, no glance, no delivery, no reaction.\",\n \"The moments pause while the flock is off screen and while the tab is hidden; there is no frame loop.\",\n ],\n },\n related: [\"mascots\", \"mascot-state\", \"bird-plate\", \"landscape\"],\n web: {\n imports: [\"Flock\"],\n examples: [\n { name: \"ridge\", title: \"The flock on its ridge\", description: \"Five birds across a stage, each at ease; neighbours glance, the pigeon delivers.\" },\n { name: \"pair\", title: \"Two birds\", description: \"The owl and the duck: they look at each other now and then.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
154
176
  },
155
177
  {
156
178
  "path": "meta.ts",
@@ -178,6 +200,13 @@
178
200
  "description": "The birds on the stage.",
179
201
  "required": true
180
202
  },
203
+ {
204
+ "name": "active",
205
+ "type": "\"falcon\" | \"owl\" | \"duck\" | \"flamingo\" | \"pigeon\" | \"lovebird\" | \"crane\" | \"magpie\" | \"beaver\" | null",
206
+ "default": "null",
207
+ "description": "A bird the page points at (a product the reader is on): it looks up and jumps once each time it changes.",
208
+ "required": false
209
+ },
181
210
  {
182
211
  "name": "courier",
183
212
  "type": "boolean",
@@ -192,6 +221,13 @@
192
221
  "description": "Two neighbours look at each other now and then. Default `true`.",
193
222
  "required": false
194
223
  },
224
+ {
225
+ "name": "greet",
226
+ "type": "boolean",
227
+ "default": "false",
228
+ "description": "The birds greet the reader once as the flock first comes into view: each jumps in turn, left to right.",
229
+ "required": false
230
+ },
195
231
  {
196
232
  "name": "random",
197
233
  "type": "(() => number)",
@@ -213,6 +249,13 @@
213
249
  "description": "A bird looks up when the pointer comes near, and jumps a little when tapped. Default `true`.",
214
250
  "required": false
215
251
  },
252
+ {
253
+ "name": "tempo",
254
+ "type": "number",
255
+ "default": "1",
256
+ "description": "How lively the moments are: 1 is calm (default), 2 doubles how often neighbours glance and the pigeon delivers.",
257
+ "required": false
258
+ },
216
259
  {
217
260
  "name": "tone",
218
261
  "type": "\"brand\" | \"own\"",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krizaka/ui",
3
- "version": "3.40.0",
3
+ "version": "3.41.0",
4
4
  "templatePurposes": {
5
5
  "convince": {
6
6
  "title": "Convince",
@@ -3142,7 +3142,7 @@
3142
3142
  "native": 2
3143
3143
  },
3144
3144
  "dependencies": [
3145
- "@krizaka/tokens@^3.40.0",
3145
+ "@krizaka/tokens@^3.41.0",
3146
3146
  "@protomaps/basemaps@5.7.2",
3147
3147
  "tailwind-variants@^3.3.1"
3148
3148
  ],
@@ -3581,7 +3581,7 @@
3581
3581
  "native": 0
3582
3582
  },
3583
3583
  "dependencies": [
3584
- "@krizaka/tokens@^3.40.0",
3584
+ "@krizaka/tokens@^3.41.0",
3585
3585
  "radix-ui@^1.7.0",
3586
3586
  "tailwind-variants@^3.3.1"
3587
3587
  ],
@@ -4244,7 +4244,7 @@
4244
4244
  "native": 0
4245
4245
  },
4246
4246
  "dependencies": [
4247
- "@krizaka/tokens@^3.40.0",
4247
+ "@krizaka/tokens@^3.41.0",
4248
4248
  "radix-ui@^1.7.0",
4249
4249
  "tailwind-variants@^3.3.1"
4250
4250
  ],
@@ -4587,7 +4587,7 @@
4587
4587
  "native": 0
4588
4588
  },
4589
4589
  "dependencies": [
4590
- "@krizaka/tokens@^3.40.0",
4590
+ "@krizaka/tokens@^3.41.0",
4591
4591
  "radix-ui@^1.7.0",
4592
4592
  "tailwind-variants@^3.3.1"
4593
4593
  ],
package/registry/map.json CHANGED
@@ -1074,7 +1074,7 @@
1074
1074
  }
1075
1075
  ],
1076
1076
  "dependencies": [
1077
- "@krizaka/tokens@^3.40.0",
1077
+ "@krizaka/tokens@^3.41.0",
1078
1078
  "@protomaps/basemaps@5.7.2",
1079
1079
  "tailwind-variants@^3.3.1"
1080
1080
  ],
@@ -618,7 +618,7 @@
618
618
  }
619
619
  ],
620
620
  "dependencies": [
621
- "@krizaka/tokens@^3.40.0",
621
+ "@krizaka/tokens@^3.41.0",
622
622
  "radix-ui@^1.7.0",
623
623
  "tailwind-variants@^3.3.1"
624
624
  ],
@@ -200,7 +200,7 @@
200
200
  "description": "`sm`, `md`, `lg`.",
201
201
  "path": "examples/progress/bar-sizes.tsx",
202
202
  "module": "@krizaka/ui/registry/examples/progress/bar-sizes",
203
- "code": "import { Progress } from \"@krizaka/ui/progress\";\n\nexport default function ProgressBarSizes() {\n return (\n <div className=\"flex flex-col gap-4\">\n <Progress label=\"Small\" size=\"sm\" value={30} />\n <Progress label=\"Medium\" size=\"md\" value={55} />\n <Progress label=\"Large\" size=\"lg\" value={80} />\n </div>\n );\n}\n"
203
+ "code": "import { Progress } from \"@krizaka/ui/progress\";\n\nexport default function ProgressBarSizes() {\n return (\n <div className=\"flex w-64 max-w-full flex-col gap-4\">\n <Progress label=\"Small\" size=\"sm\" value={30} />\n <Progress label=\"Medium\" size=\"md\" value={55} />\n <Progress label=\"Large\" size=\"lg\" value={80} />\n </div>\n );\n}\n"
204
204
  },
205
205
  {
206
206
  "name": "bar-indeterminate",
@@ -342,7 +342,7 @@
342
342
  }
343
343
  ],
344
344
  "dependencies": [
345
- "@krizaka/tokens@^3.40.0",
345
+ "@krizaka/tokens@^3.41.0",
346
346
  "radix-ui@^1.7.0",
347
347
  "tailwind-variants@^3.3.1"
348
348
  ],
@@ -329,7 +329,7 @@
329
329
  }
330
330
  ],
331
331
  "dependencies": [
332
- "@krizaka/tokens@^3.40.0",
332
+ "@krizaka/tokens@^3.41.0",
333
333
  "radix-ui@^1.7.0",
334
334
  "tailwind-variants@^3.3.1"
335
335
  ],