@salemcobalt/ui 0.2.0-rc.11 → 0.2.0-rc.13

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/index.js CHANGED
@@ -442,7 +442,19 @@ function XIcon(props) {
442
442
 
443
443
  // src/components/Dialog/Dialog.tsx
444
444
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
445
- function Root({ dismissible = true, onOpenChange, open, defaultOpen, children }) {
445
+ var REQUESTABLE = /* @__PURE__ */ new Set([
446
+ "escape-key",
447
+ "outside-press",
448
+ "close-press"
449
+ ]);
450
+ function Root({
451
+ dismissible = true,
452
+ onOpenChange,
453
+ onRequestClose,
454
+ open,
455
+ defaultOpen,
456
+ children
457
+ }) {
446
458
  return /* @__PURE__ */ jsx6(
447
459
  BaseDialog.Root,
448
460
  {
@@ -454,6 +466,11 @@ function Root({ dismissible = true, onOpenChange, open, defaultOpen, children })
454
466
  details.cancel();
455
467
  return;
456
468
  }
469
+ if (!next && onRequestClose && REQUESTABLE.has(details.reason)) {
470
+ details.cancel();
471
+ onRequestClose(details.reason);
472
+ return;
473
+ }
457
474
  onOpenChange?.(next);
458
475
  },
459
476
  children
@@ -3133,6 +3150,331 @@ function BroomIcon({ sweeping = false, size = "lg", title, className, ...rest })
3133
3150
  );
3134
3151
  }
3135
3152
 
3153
+ // src/components/FullScreenFlow/FullScreenFlow.tsx
3154
+ import {
3155
+ Children as Children2,
3156
+ createContext as createContext2,
3157
+ useCallback as useCallback2,
3158
+ useContext as useContext2,
3159
+ useEffect as useEffect6,
3160
+ useEffectEvent,
3161
+ useId as useId5,
3162
+ useMemo as useMemo3,
3163
+ useRef as useRef6,
3164
+ useState as useState8
3165
+ } from "react";
3166
+ import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
3167
+ var FlowContext = createContext2({ announce: () => {
3168
+ } });
3169
+ var FrameContext = createContext2(void 0);
3170
+ var ENTER_IGNORES = 'textarea, button, a[href], summary, select, [contenteditable], [role="combobox"], [data-flow-keys="local"]';
3171
+ var ARROW_IGNORES = 'input, textarea, select, button, a[href], summary, [contenteditable], [role="radiogroup"], [role="slider"], [role="listbox"], [role="tablist"], [role="menu"], [role="grid"], [role="combobox"], [data-flow-keys="local"]';
3172
+ function Root7({
3173
+ open = true,
3174
+ onRequestClose,
3175
+ onNext,
3176
+ onBack,
3177
+ decoration,
3178
+ className,
3179
+ children
3180
+ }) {
3181
+ const popupRef = useRef6(null);
3182
+ const [message, setMessage] = useState8("");
3183
+ const timer = useRef6(void 0);
3184
+ const announce = useCallback2((next) => {
3185
+ setMessage("");
3186
+ clearTimeout(timer.current);
3187
+ timer.current = setTimeout(() => setMessage(next), 30);
3188
+ }, []);
3189
+ useEffect6(() => () => clearTimeout(timer.current), []);
3190
+ const context = useMemo3(() => ({ announce }), [announce]);
3191
+ const handleKeyDown = (event) => {
3192
+ if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
3193
+ if (event.nativeEvent.isComposing) return;
3194
+ const target = event.target;
3195
+ if (!event.currentTarget.contains(target)) return;
3196
+ if (event.key === "Enter") {
3197
+ if (!onNext || target.closest(ENTER_IGNORES)) return;
3198
+ event.preventDefault();
3199
+ onNext();
3200
+ return;
3201
+ }
3202
+ if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return;
3203
+ if (target.closest(ARROW_IGNORES)) return;
3204
+ const rtl = getComputedStyle(event.currentTarget).direction === "rtl";
3205
+ const forward = event.key === "ArrowRight" !== rtl;
3206
+ const handler = forward ? onNext : onBack;
3207
+ if (!handler) return;
3208
+ event.preventDefault();
3209
+ handler();
3210
+ };
3211
+ return /* @__PURE__ */ jsx34(
3212
+ Dialog.Root,
3213
+ {
3214
+ open,
3215
+ onRequestClose: (reason) => {
3216
+ if (reason !== "outside-press") onRequestClose(reason);
3217
+ },
3218
+ children: /* @__PURE__ */ jsx34(
3219
+ Dialog.Content,
3220
+ {
3221
+ ref: popupRef,
3222
+ variant: "fullscreen",
3223
+ className: cx("sc-flow", className),
3224
+ initialFocus: () => popupRef.current?.querySelector(".sc-flow__step-title") ?? true,
3225
+ onKeyDown: handleKeyDown,
3226
+ children: /* @__PURE__ */ jsxs29(FlowContext.Provider, { value: context, children: [
3227
+ decoration ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__decoration", "aria-hidden": "true", children: decoration }) : null,
3228
+ children,
3229
+ /* @__PURE__ */ jsx34("div", { className: "sc-visually-hidden", "aria-live": "polite", "aria-atomic": "true", children: message })
3230
+ ] })
3231
+ }
3232
+ )
3233
+ }
3234
+ );
3235
+ }
3236
+ function Header2({
3237
+ title,
3238
+ logo,
3239
+ compactTitle,
3240
+ status,
3241
+ closeLabel = "Close",
3242
+ className,
3243
+ children,
3244
+ ...rest
3245
+ }) {
3246
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__header", className), ...rest, children: [
3247
+ /* @__PURE__ */ jsxs29("div", { className: "sc-flow__heading", "data-compact": compactTitle ? "" : void 0, children: [
3248
+ logo ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__logo", "aria-hidden": "true", children: logo }) : null,
3249
+ /* @__PURE__ */ jsx34(Dialog.Title, { className: "sc-flow__title", children: title }),
3250
+ compactTitle ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__compact-title", children: compactTitle }) : null
3251
+ ] }),
3252
+ children,
3253
+ status ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__status", children: status }) : null,
3254
+ /* @__PURE__ */ jsx34(
3255
+ Dialog.Close,
3256
+ {
3257
+ className: "sc-flow__close",
3258
+ render: /* @__PURE__ */ jsx34(IconButton, { label: closeLabel, "aria-keyshortcuts": "Escape" }),
3259
+ children: /* @__PURE__ */ jsx34(XIcon, { size: "lg" })
3260
+ }
3261
+ )
3262
+ ] });
3263
+ }
3264
+ function Progress2({
3265
+ chapters,
3266
+ step,
3267
+ label,
3268
+ listLabel = "Progress",
3269
+ className,
3270
+ ...rest
3271
+ }) {
3272
+ const starts = chapters.reduce(
3273
+ (acc, chapter, i) => [...acc, i === 0 ? 0 : acc[i - 1] + chapters[i - 1].steps],
3274
+ []
3275
+ );
3276
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__progress", className), ...rest, children: [
3277
+ label ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__progress-label", children: label }) : null,
3278
+ /* @__PURE__ */ jsx34("ol", { className: "sc-flow__segments", "aria-label": listLabel, children: chapters.map((chapter, i) => {
3279
+ const from = starts[i];
3280
+ const current = step > from && step <= from + chapter.steps;
3281
+ const done = Math.min(chapter.steps, Math.max(0, step - 1 - from)) + (current ? 0.5 : 0);
3282
+ const percent = chapter.steps > 0 ? Math.min(100, done / chapter.steps * 100) : 0;
3283
+ return /* @__PURE__ */ jsxs29(
3284
+ "li",
3285
+ {
3286
+ className: "sc-flow__segment",
3287
+ style: { flexGrow: chapter.steps },
3288
+ "aria-current": current ? "step" : void 0,
3289
+ children: [
3290
+ /* @__PURE__ */ jsx34("span", { className: "sc-flow__segment-fill", style: { inlineSize: `${percent}%` } }),
3291
+ /* @__PURE__ */ jsx34("span", { className: "sc-visually-hidden", children: chapter.label })
3292
+ ]
3293
+ },
3294
+ chapter.label
3295
+ );
3296
+ }) })
3297
+ ] });
3298
+ }
3299
+ function Body3({ className, ...rest }) {
3300
+ return /* @__PURE__ */ jsx34("div", { className: cx("sc-flow__body", className), ...rest });
3301
+ }
3302
+ function Rail({
3303
+ "aria-label": ariaLabel = "Steps",
3304
+ footer,
3305
+ className,
3306
+ children,
3307
+ ...rest
3308
+ }) {
3309
+ return /* @__PURE__ */ jsxs29("nav", { className: cx("sc-flow__rail", className), "aria-label": ariaLabel, ...rest, children: [
3310
+ children,
3311
+ footer ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__rail-note", children: footer }) : null
3312
+ ] });
3313
+ }
3314
+ function RailGroup({ label, className, children, ...rest }) {
3315
+ const id = useId5();
3316
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__rail-group", className), ...rest, children: [
3317
+ /* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-label", id, children: label }),
3318
+ /* @__PURE__ */ jsx34("ol", { className: "sc-flow__rail-list", "aria-labelledby": id, children })
3319
+ ] });
3320
+ }
3321
+ function RailItem({
3322
+ current = false,
3323
+ done = false,
3324
+ doneLabel = "done",
3325
+ adornment,
3326
+ type = "button",
3327
+ className,
3328
+ children,
3329
+ ...rest
3330
+ }) {
3331
+ return /* @__PURE__ */ jsx34("li", { className: "sc-flow__rail-entry", children: /* @__PURE__ */ jsxs29(
3332
+ "button",
3333
+ {
3334
+ type,
3335
+ className: cx("sc-flow__rail-item", className),
3336
+ "aria-current": current ? "step" : void 0,
3337
+ "data-done": done || void 0,
3338
+ ...rest,
3339
+ children: [
3340
+ /* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-mark", "aria-hidden": "true", children: done ? /* @__PURE__ */ jsx34(CheckIcon, { size: "sm" }) : null }),
3341
+ /* @__PURE__ */ jsxs29("span", { className: "sc-flow__rail-text", children: [
3342
+ children,
3343
+ done ? /* @__PURE__ */ jsxs29("span", { className: "sc-visually-hidden", children: [
3344
+ ", ",
3345
+ doneLabel
3346
+ ] }) : null
3347
+ ] }),
3348
+ adornment ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-adornment", children: adornment }) : null
3349
+ ]
3350
+ }
3351
+ ) });
3352
+ }
3353
+ function Viewport2({ direction = "forward", className, children, ...rest }) {
3354
+ const element = Children2.only(children);
3355
+ const key = String(element.key ?? "");
3356
+ const [state, setState] = useState8({
3357
+ current: { key, element, direction },
3358
+ leaving: null,
3359
+ moved: false
3360
+ });
3361
+ if (state.current.key !== key) {
3362
+ setState({
3363
+ current: { key, element, direction },
3364
+ leaving: { ...state.current, direction },
3365
+ moved: true
3366
+ });
3367
+ } else if (state.current.element !== element) {
3368
+ setState((s) => ({ ...s, current: { ...s.current, element } }));
3369
+ }
3370
+ const finishExit = useCallback2((leftKey) => {
3371
+ setState((s) => s.leaving?.key === leftKey ? { ...s, leaving: null } : s);
3372
+ }, []);
3373
+ const ref = useRef6(null);
3374
+ useEffect6(() => {
3375
+ if (state.moved && ref.current) ref.current.scrollTop = 0;
3376
+ }, [key, state.moved]);
3377
+ const frames = [];
3378
+ if (state.leaving && state.leaving.key !== key) frames.push({ frame: state.leaving, phase: "exit" });
3379
+ frames.push({
3380
+ frame: { key, element, direction: state.current.direction },
3381
+ phase: state.moved ? "enter" : void 0
3382
+ });
3383
+ return /* @__PURE__ */ jsx34("div", { ref, className: cx("sc-flow__viewport", className), ...rest, children: frames.map(({ frame, phase }) => /* @__PURE__ */ jsx34(
3384
+ FrameView,
3385
+ {
3386
+ frameKey: frame.key,
3387
+ phase,
3388
+ direction: frame.direction,
3389
+ onExited: finishExit,
3390
+ children: frame.element
3391
+ },
3392
+ frame.key
3393
+ )) });
3394
+ }
3395
+ function FrameView({
3396
+ frameKey,
3397
+ phase,
3398
+ direction,
3399
+ onExited,
3400
+ children
3401
+ }) {
3402
+ const ref = useRef6(null);
3403
+ useEffect6(() => {
3404
+ if (phase !== "exit") return;
3405
+ let cancelled = false;
3406
+ const el = ref.current;
3407
+ const animations = el && typeof el.getAnimations === "function" ? el.getAnimations() : [];
3408
+ const done = () => {
3409
+ if (!cancelled) onExited(frameKey);
3410
+ };
3411
+ Promise.all(animations.map((a) => a.finished)).then(done, done);
3412
+ return () => {
3413
+ cancelled = true;
3414
+ };
3415
+ }, [phase, frameKey, onExited]);
3416
+ return /* @__PURE__ */ jsx34(
3417
+ "div",
3418
+ {
3419
+ ref,
3420
+ className: "sc-flow__frame",
3421
+ "data-phase": phase,
3422
+ "data-direction": direction,
3423
+ inert: phase === "exit",
3424
+ children: /* @__PURE__ */ jsx34(FrameContext.Provider, { value: phase, children })
3425
+ }
3426
+ );
3427
+ }
3428
+ function Step({
3429
+ title,
3430
+ eyebrow,
3431
+ description,
3432
+ announcement,
3433
+ className,
3434
+ children,
3435
+ ...rest
3436
+ }) {
3437
+ const id = useId5();
3438
+ const titleRef = useRef6(null);
3439
+ const phase = useContext2(FrameContext);
3440
+ const { announce } = useContext2(FlowContext);
3441
+ const message = announcement ?? (typeof title === "string" ? title : void 0);
3442
+ const arrive = useEffectEvent(() => {
3443
+ titleRef.current?.focus({ preventScroll: true });
3444
+ if (message) announce(message);
3445
+ });
3446
+ useEffect6(() => {
3447
+ if (phase === "enter") arrive();
3448
+ }, [phase]);
3449
+ return /* @__PURE__ */ jsxs29("section", { className: cx("sc-flow__step", className), "aria-labelledby": id, ...rest, children: [
3450
+ /* @__PURE__ */ jsxs29("div", { className: "sc-flow__step-head", children: [
3451
+ eyebrow ? /* @__PURE__ */ jsx34("p", { className: "sc-flow__eyebrow", children: eyebrow }) : null,
3452
+ /* @__PURE__ */ jsx34("h2", { className: "sc-flow__step-title", id, ref: titleRef, tabIndex: -1, children: title }),
3453
+ description ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__step-description", children: description }) : null
3454
+ ] }),
3455
+ children
3456
+ ] });
3457
+ }
3458
+ function Footer({ back, hint, className, children, ...rest }) {
3459
+ return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__footer", className), ...rest, children: [
3460
+ back ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-back", children: back }) : null,
3461
+ hint ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-hint", children: hint }) : null,
3462
+ /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-actions", children })
3463
+ ] });
3464
+ }
3465
+ var FullScreenFlow = {
3466
+ Root: Root7,
3467
+ Header: Header2,
3468
+ Progress: Progress2,
3469
+ Body: Body3,
3470
+ Rail,
3471
+ RailGroup,
3472
+ RailItem,
3473
+ Viewport: Viewport2,
3474
+ Step,
3475
+ Footer
3476
+ };
3477
+
3136
3478
  // src/index.ts
3137
3479
  var version = "0.1.1";
3138
3480
  export {
@@ -3172,6 +3514,7 @@ export {
3172
3514
  FilePreviewDialog,
3173
3515
  FilterIcon,
3174
3516
  FlagIcon,
3517
+ FullScreenFlow,
3175
3518
  Heading,
3176
3519
  Icon,
3177
3520
  IconButton,