weifuwu 0.51.1 → 0.52.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.
@@ -536,6 +536,7 @@ function createApp() {
536
536
  let _rendering = false;
537
537
  let _dirtyBatch = /* @__PURE__ */ new Set();
538
538
  let _dirtyScheduled = false;
539
+ const _mediaRegistry = /* @__PURE__ */ new Map();
539
540
  function renderByIds(ids) {
540
541
  if (_rendering) return;
541
542
  _rendering = true;
@@ -635,6 +636,63 @@ function createApp() {
635
636
  if (selfId) ctx.ui.dirty([selfId]);
636
637
  });
637
638
  },
639
+ /**
640
+ * 响应式媒体查询:注册监听,值变化时自动 dirty
641
+ *
642
+ * 用法:
643
+ * const $ = ctx.ui.$()
644
+ * ctx.ui.useMedia('(max-width: 640px)', (v) => { $.isMobile = v })
645
+ *
646
+ * callback 会立即执行一次(取当前值),之后在变化时再次执行
647
+ */
648
+ useMedia: function(query, callback) {
649
+ const selfId = getSelfId(this);
650
+ const key = `media:${selfId}:${query}`;
651
+ if (!_mediaRegistry.has(key)) {
652
+ const mql = window.matchMedia(query);
653
+ callback(mql.matches);
654
+ const handler = (e) => callback(e.matches);
655
+ mql.addEventListener("change", handler);
656
+ _mediaRegistry.set(key, { mql, handler });
657
+ }
658
+ },
659
+ /**
660
+ * 响应式断点:注册命名断点监听,值变化时自动 dirty
661
+ *
662
+ * 用法:
663
+ * const $ = ctx.ui.$()
664
+ * ctx.ui.useBreakpoint((vp) => { $.vp = vp })
665
+ * // vp: 'mobile' | 'tablet' | 'desktop'
666
+ *
667
+ * 自定义断点:
668
+ * ctx.ui.useBreakpoint(
669
+ * { narrow: '(max-width: 480px)', wide: '(min-width: 1200px)' },
670
+ * (vp) => { $.size = vp }
671
+ * )
672
+ */
673
+ useBreakpoint: function(bpsOrCallback, callback) {
674
+ const bps = typeof bpsOrCallback === "function" ? { mobile: "(max-width: 639px)", tablet: "(min-width: 640px) and (max-width: 1023px)", desktop: "(min-width: 1024px)" } : bpsOrCallback;
675
+ const cb = typeof bpsOrCallback === "function" ? bpsOrCallback : callback;
676
+ const selfId = getSelfId(this);
677
+ const key = `bp:${selfId}`;
678
+ function evaluate() {
679
+ for (const [name, query] of Object.entries(bps)) {
680
+ if (window.matchMedia(query).matches) return name;
681
+ }
682
+ return Object.keys(bps)[0] ?? "";
683
+ }
684
+ if (!_mediaRegistry.has(key)) {
685
+ cb(evaluate());
686
+ const handlers = [];
687
+ for (const query of Object.values(bps)) {
688
+ const mql = window.matchMedia(query);
689
+ const handler = () => cb(evaluate());
690
+ mql.addEventListener("change", handler);
691
+ handlers.push(() => mql.removeEventListener("change", handler));
692
+ }
693
+ _mediaRegistry.set(key, { mql: null, handler: null });
694
+ }
695
+ },
638
696
  /** 注册组件实例的自定义 ID(用于跨组件精准刷新) */
639
697
  selfId: function(name) {
640
698
  if (typeof name !== "string" || !name) {
@@ -110,6 +110,12 @@
110
110
  --wf-accent-color: var(--wf-color-primary);
111
111
  --wf-caret-color: var(--wf-color-primary);
112
112
 
113
+ /* ── 断点 ── */
114
+ --wf-bp-sm: 640px;
115
+ --wf-bp-md: 768px;
116
+ --wf-bp-lg: 1024px;
117
+ --wf-bp-xl: 1280px;
118
+
113
119
  /* ── 透明度 ── */
114
120
  --wf-opacity-disabled: 0.5;
115
121
  --wf-opacity-overlay: 0.4;
@@ -314,6 +320,9 @@ code {
314
320
  flex-direction: column;
315
321
  gap: var(--wf-gap, var(--wf-gap-md));
316
322
  }
323
+ @media (min-width: 640px) { .wf-stack\@sm { flex-direction: row; align-items: var(--wf-align, center); } }
324
+ @media (min-width: 768px) { .wf-stack\@md { flex-direction: row; align-items: var(--wf-align, center); } }
325
+ @media (min-width: 1024px) { .wf-stack\@lg { flex-direction: row; align-items: var(--wf-align, center); } }
317
326
 
318
327
  /* stack-reverse — 纵向反向堆叠 */
319
328
  .wf-stack-reverse {
@@ -321,6 +330,9 @@ code {
321
330
  flex-direction: column-reverse;
322
331
  gap: var(--wf-gap, var(--wf-gap-md));
323
332
  }
333
+ @media (min-width: 640px) { .wf-stack-reverse\@sm { flex-direction: row-reverse; align-items: var(--wf-align, center); } }
334
+ @media (min-width: 768px) { .wf-stack-reverse\@md { flex-direction: row-reverse; align-items: var(--wf-align, center); } }
335
+ @media (min-width: 1024px) { .wf-stack-reverse\@lg { flex-direction: row-reverse; align-items: var(--wf-align, center); } }
324
336
 
325
337
  /* row — 横向排列 */
326
338
  .wf-row {
@@ -329,6 +341,9 @@ code {
329
341
  gap: var(--wf-gap, var(--wf-gap-md));
330
342
  align-items: var(--wf-align, center);
331
343
  }
344
+ @media (min-width: 640px) { .wf-row\@sm { flex-direction: row; flex-wrap: wrap; } }
345
+ @media (min-width: 768px) { .wf-row\@md { flex-direction: row; flex-wrap: wrap; } }
346
+ @media (min-width: 1024px) { .wf-row\@lg { flex-direction: row; flex-wrap: wrap; } }
332
347
 
333
348
  /* row-reverse — 横向反向排列 */
334
349
  .wf-row-reverse {
@@ -338,6 +353,9 @@ code {
338
353
  gap: var(--wf-gap, var(--wf-gap-md));
339
354
  align-items: var(--wf-align, center);
340
355
  }
356
+ @media (min-width: 640px) { .wf-row-reverse\@sm { flex-direction: row-reverse; flex-wrap: wrap; } }
357
+ @media (min-width: 768px) { .wf-row-reverse\@md { flex-direction: row-reverse; flex-wrap: wrap; } }
358
+ @media (min-width: 1024px) { .wf-row-reverse\@lg { flex-direction: row-reverse; flex-wrap: wrap; } }
341
359
 
342
360
  /* split — 两端展开 */
343
361
  .wf-split {
@@ -486,11 +504,17 @@ code {
486
504
  .wf-hidden {
487
505
  display: none;
488
506
  }
507
+ @media (min-width: 640px) { .wf-hidden\@sm { display: none; } }
508
+ @media (min-width: 768px) { .wf-hidden\@md { display: none; } }
509
+ @media (min-width: 1024px) { .wf-hidden\@lg { display: none; } }
489
510
 
490
511
  /* block — 块级显示 */
491
512
  .wf-block {
492
513
  display: block;
493
514
  }
515
+ @media (min-width: 640px) { .wf-block\@sm { display: block; } }
516
+ @media (min-width: 768px) { .wf-block\@md { display: block; } }
517
+ @media (min-width: 1024px) { .wf-block\@lg { display: block; } }
494
518
 
495
519
  /* inline — 行内显示 */
496
520
  .wf-inline {
@@ -110,6 +110,12 @@
110
110
  --wf-accent-color: var(--wf-color-primary);
111
111
  --wf-caret-color: var(--wf-color-primary);
112
112
 
113
+ /* ── 断点 ── */
114
+ --wf-bp-sm: 640px;
115
+ --wf-bp-md: 768px;
116
+ --wf-bp-lg: 1024px;
117
+ --wf-bp-xl: 1280px;
118
+
113
119
  /* ── 透明度 ── */
114
120
  --wf-opacity-disabled: 0.5;
115
121
  --wf-opacity-overlay: 0.4;
@@ -314,6 +320,9 @@ code {
314
320
  flex-direction: column;
315
321
  gap: var(--wf-gap, var(--wf-gap-md));
316
322
  }
323
+ @media (min-width: 640px) { .wf-stack\@sm { flex-direction: row; align-items: var(--wf-align, center); } }
324
+ @media (min-width: 768px) { .wf-stack\@md { flex-direction: row; align-items: var(--wf-align, center); } }
325
+ @media (min-width: 1024px) { .wf-stack\@lg { flex-direction: row; align-items: var(--wf-align, center); } }
317
326
 
318
327
  /* stack-reverse — 纵向反向堆叠 */
319
328
  .wf-stack-reverse {
@@ -321,6 +330,9 @@ code {
321
330
  flex-direction: column-reverse;
322
331
  gap: var(--wf-gap, var(--wf-gap-md));
323
332
  }
333
+ @media (min-width: 640px) { .wf-stack-reverse\@sm { flex-direction: row-reverse; align-items: var(--wf-align, center); } }
334
+ @media (min-width: 768px) { .wf-stack-reverse\@md { flex-direction: row-reverse; align-items: var(--wf-align, center); } }
335
+ @media (min-width: 1024px) { .wf-stack-reverse\@lg { flex-direction: row-reverse; align-items: var(--wf-align, center); } }
324
336
 
325
337
  /* row — 横向排列 */
326
338
  .wf-row {
@@ -329,6 +341,9 @@ code {
329
341
  gap: var(--wf-gap, var(--wf-gap-md));
330
342
  align-items: var(--wf-align, center);
331
343
  }
344
+ @media (min-width: 640px) { .wf-row\@sm { flex-direction: row; flex-wrap: wrap; } }
345
+ @media (min-width: 768px) { .wf-row\@md { flex-direction: row; flex-wrap: wrap; } }
346
+ @media (min-width: 1024px) { .wf-row\@lg { flex-direction: row; flex-wrap: wrap; } }
332
347
 
333
348
  /* row-reverse — 横向反向排列 */
334
349
  .wf-row-reverse {
@@ -338,6 +353,9 @@ code {
338
353
  gap: var(--wf-gap, var(--wf-gap-md));
339
354
  align-items: var(--wf-align, center);
340
355
  }
356
+ @media (min-width: 640px) { .wf-row-reverse\@sm { flex-direction: row-reverse; flex-wrap: wrap; } }
357
+ @media (min-width: 768px) { .wf-row-reverse\@md { flex-direction: row-reverse; flex-wrap: wrap; } }
358
+ @media (min-width: 1024px) { .wf-row-reverse\@lg { flex-direction: row-reverse; flex-wrap: wrap; } }
341
359
 
342
360
  /* split — 两端展开 */
343
361
  .wf-split {
@@ -486,11 +504,17 @@ code {
486
504
  .wf-hidden {
487
505
  display: none;
488
506
  }
507
+ @media (min-width: 640px) { .wf-hidden\@sm { display: none; } }
508
+ @media (min-width: 768px) { .wf-hidden\@md { display: none; } }
509
+ @media (min-width: 1024px) { .wf-hidden\@lg { display: none; } }
489
510
 
490
511
  /* block — 块级显示 */
491
512
  .wf-block {
492
513
  display: block;
493
514
  }
515
+ @media (min-width: 640px) { .wf-block\@sm { display: block; } }
516
+ @media (min-width: 768px) { .wf-block\@md { display: block; } }
517
+ @media (min-width: 1024px) { .wf-block\@lg { display: block; } }
494
518
 
495
519
  /* inline — 行内显示 */
496
520
  .wf-inline {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "weifuwu",
3
3
  "type": "module",
4
- "version": "0.51.1",
4
+ "version": "0.52.0",
5
5
  "description": "AI SaaS framework — (req, ctx) => Response",
6
6
  "exports": {
7
7
  ".": {